<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN">
<HTML>
<HEAD>
<LINK REL=STYLESHEET TYPE="text/css" HREF="../../stylesheet.css" TITLE="Style">
<META NAME="GENERATOR" CONTENT="Java2HTML Version 1.5">
<TITLE>czestmyr.jjsched.DatabaseConnector (Java2HTML)</TITLE>
</HEAD>
<BODY><TABLE id="Header" border="0" cellpadding="0" cellspacing="0" width="100%">
<tr>
<td colspan="2" width="33%">&nbsp;</td>
<td align="center" colspan="2" width="33%">
<font size="4">DatabaseConnector.java</font>
</td>
<td align="right" colspan="2" width="33%">&nbsp;</td>
</tr>
</TABLE>
<pre ID="Classes">
<A NAME="1"></A><FONT ID="MultiLineComment">/*  This file is a part of JJSched source code
<A NAME="2"></A>    JJSched - Java Jabber Scheduler - a simple Jabber scheduling application
<A NAME="3"></A>    Copyright (C) 2008 Cestmir "CZestmyr" Houska
<A NAME="4"></A>
<A NAME="5"></A>    This program is free software: you can redistribute it and/or modify
<A NAME="6"></A>    it under the terms of the GNU General Public License as published by
<A NAME="7"></A>    the Free Software Foundation, either version 3 of the License, or
<A NAME="8"></A>    (at your option) any later version.
<A NAME="9"></A>
<A NAME="10"></A>    This program is distributed in the hope that it will be useful,
<A NAME="11"></A>    but WITHOUT ANY WARRANTY; without even the implied warranty of
<A NAME="12"></A>    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
<A NAME="13"></A>    GNU General Public License for more details.
<A NAME="14"></A>
<A NAME="15"></A>    You should have received a copy of the GNU General Public License
<A NAME="16"></A>    along with this program.  If not, see &lt;http://www.gnu.org/licenses/&gt; */</FONT>
<A NAME="17"></A>
<A NAME="18"></A><FONT ID="Package">package</FONT> czestmyr.jjsched;
<A NAME="19"></A>
<A NAME="20"></A><FONT ID="Import">import</FONT> java.util.*;
<A NAME="21"></A><FONT ID="Import">import</FONT> java.util.concurrent.locks.*;
<A NAME="22"></A><FONT ID="Import">import</FONT> java.sql.*;
<A NAME="23"></A><FONT ID="Import">import</FONT> java.text.*;
<A NAME="24"></A>
<A NAME="25"></A><FONT ID="Import">import</FONT> java.nio.charset.*;
<A NAME="26"></A>
<A NAME="27"></A><FONT ID="FormalComment">/**
<A NAME="28"></A> * Provides the connection to the database server.
<A NAME="29"></A> * This class performs only basic integrity checks and prevents for example adding of users.
<A NAME="30"></A> * that are not registered to JJSched or setting privileges to illegal values.
<A NAME="31"></A> * But it does not check whether the user has privileges to do an action.
<A NAME="32"></A> */</FONT>
<A NAME="33"></A><FONT ID="Public">public</FONT> <FONT ID="Class">class</FONT> DatabaseConnector{
<A NAME="34"></A>    DatabaseConnector(<A HREF="../../czestmyr/jjsched/Config.java.html">Config</A> c, <A HREF="../../czestmyr/jjsched/TimeHandler.java.html">TimeHandler</A> newTime){
<A NAME="35"></A>        conf = c;
<A NAME="36"></A>        timeHandler = newTime;
<A NAME="37"></A>        userCache = <FONT ID="New">new</FONT> HashMap&lt;String, UserData&gt;();
<A NAME="38"></A>        adminCache = <FONT ID="New">new</FONT> HashMap&lt;String, Integer&gt;();
<A NAME="39"></A>    }
<A NAME="40"></A>
<A NAME="41"></A>    <FONT ID="FormalComment">/**
<A NAME="42"></A>     * Tries to connect to the database as specified in the config file.
<A NAME="43"></A>     * 
<A NAME="44"></A>     * @param   autocreate  Whether the connector should automatically create new DB tables if they are not present
<A NAME="45"></A>     *                      or broken
<A NAME="46"></A>     * @throws  Exception   If the connection could not be created or established or in case of database inconsistency.
<A NAME="47"></A>     */</FONT>
<A NAME="48"></A>    <FONT ID="Public">public</FONT> <FONT ID="Void">void</FONT> connect(<FONT ID="Boolean">boolean</FONT> autocreate) <FONT ID="Throws">throws</FONT> Exception{
<A NAME="49"></A>        <FONT ID="SingleLineComment">//Load the mysql DB first
<A NAME="50"></A></FONT>        <FONT ID="Try">try</FONT> {
<A NAME="51"></A>            Class.forName(<FONT ID="StringLiteral">"com.mysql.jdbc.Driver"</FONT>);
<A NAME="52"></A>        } <FONT ID="Catch">catch</FONT> (ClassNotFoundException e) {
<A NAME="53"></A>            <FONT ID="Throw">throw</FONT> <FONT ID="New">new</FONT> Exception(<FONT ID="StringLiteral">"The jdbc mysql driver could not be found\nCheck, whether you have jdbc installed.\nOriginal exception:\n"</FONT>+e.getMessage());
<A NAME="54"></A>        }
<A NAME="55"></A>
<A NAME="56"></A>        <FONT ID="SingleLineComment">//Get sql connection parameters from the config file
<A NAME="57"></A></FONT>        String host, port, scheme, user, pass;
<A NAME="58"></A>        host = conf.getString(<FONT ID="StringLiteral">"MySQLHost"</FONT>);
<A NAME="59"></A>        port = conf.getString(<FONT ID="StringLiteral">"MySQLPort"</FONT>);
<A NAME="60"></A>        scheme = conf.getString(<FONT ID="StringLiteral">"MySQLScheme"</FONT>);
<A NAME="61"></A>        user = conf.getString(<FONT ID="StringLiteral">"MySQLUsername"</FONT>);
<A NAME="62"></A>        pass = conf.getString(<FONT ID="StringLiteral">"MySQLPassword"</FONT>);
<A NAME="63"></A>        <FONT ID="If">if</FONT> (host == <FONT ID="Null">null</FONT>) <FONT ID="Throw">throw</FONT> <FONT ID="New">new</FONT> Exception(<FONT ID="StringLiteral">"Config error: specify 'MySQLHost' option in config file!"</FONT>);
<A NAME="64"></A>        <FONT ID="If">if</FONT> (port == <FONT ID="Null">null</FONT>) <FONT ID="Throw">throw</FONT> <FONT ID="New">new</FONT> Exception(<FONT ID="StringLiteral">"Config error: specify 'MySQLPort' option in config file!"</FONT>);
<A NAME="65"></A>        <FONT ID="If">if</FONT> (scheme == <FONT ID="Null">null</FONT>) <FONT ID="Throw">throw</FONT> <FONT ID="New">new</FONT> Exception(<FONT ID="StringLiteral">"Config error: specify 'MySQLScheme' option in config file!"</FONT>);
<A NAME="66"></A>        <FONT ID="If">if</FONT> (user == <FONT ID="Null">null</FONT>) <FONT ID="Throw">throw</FONT> <FONT ID="New">new</FONT> Exception(<FONT ID="StringLiteral">"Config error: specify 'MySQLUsername' option in config file!"</FONT>);
<A NAME="67"></A>        <FONT ID="If">if</FONT> (pass == <FONT ID="Null">null</FONT>) <FONT ID="Throw">throw</FONT> <FONT ID="New">new</FONT> Exception(<FONT ID="StringLiteral">"Config error: specify 'MySQLPassword' option in config file!"</FONT>);
<A NAME="68"></A>        String url = <FONT ID="StringLiteral">"jdbc:mysql://"</FONT>+host+<FONT ID="StringLiteral">":"</FONT>+port+<FONT ID="StringLiteral">"/"</FONT>+scheme+<FONT ID="StringLiteral">"?characterEncoding=utf8"</FONT>;
<A NAME="69"></A>        conn = DriverManager.getConnection(url, user, pass);
<A NAME="70"></A>        statement = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,
<A NAME="71"></A>                                         ResultSet.CONCUR_READ_ONLY);
<A NAME="72"></A>        resultStatement = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,
<A NAME="73"></A>                                               ResultSet.CONCUR_READ_ONLY);
<A NAME="74"></A>
<A NAME="75"></A>        <FONT ID="Try">try</FONT> {
<A NAME="76"></A>            checkDB();
<A NAME="77"></A>        } <FONT ID="Catch">catch</FONT> (Exception e) {
<A NAME="78"></A>            <FONT ID="SingleLineComment">//If autocreate option is not specified, throw an exception. Else continue and reset the DB
<A NAME="79"></A></FONT>            <FONT ID="If">if</FONT> (!autocreate)
<A NAME="80"></A>                <FONT ID="Throw">throw</FONT> <FONT ID="New">new</FONT> Exception(e.getMessage()+<FONT ID="StringLiteral">"\n    Note: If you don't want this error, launch jjsched with option"</FONT>+
<A NAME="81"></A>                                                   <FONT ID="StringLiteral">" --autocreate, but beware - this option DROPS all interfering"</FONT>+
<A NAME="82"></A>                                                   <FONT ID="StringLiteral">" tables and replaces them with the correct tables for jjsched"</FONT>);
<A NAME="83"></A>        }
<A NAME="84"></A>
<A NAME="85"></A>        <FONT ID="If">if</FONT> (autocreate) <FONT ID="Try">try</FONT> {
<A NAME="86"></A>            createTables();
<A NAME="87"></A>        } <FONT ID="Catch">catch</FONT> (Exception e) {
<A NAME="88"></A>            <FONT ID="Throw">throw</FONT> <FONT ID="New">new</FONT> Exception(<FONT ID="StringLiteral">"Error while creating new tables:\n"</FONT>+e.getMessage());
<A NAME="89"></A>        }
<A NAME="90"></A>
<A NAME="91"></A>        mirrorCaches();
<A NAME="92"></A>    }
<A NAME="93"></A>
<A NAME="94"></A>    <FONT ID="FormalComment">/** Locks the data read lock */</FONT>
<A NAME="95"></A>    <FONT ID="Private">private</FONT> <FONT ID="Void">void</FONT> lr() {
<A NAME="96"></A>        dataLock.readLock().lock();
<A NAME="97"></A>    }
<A NAME="98"></A>
<A NAME="99"></A>    <FONT ID="FormalComment">/** Locks the data write lock */</FONT>
<A NAME="100"></A>    <FONT ID="Private">private</FONT> <FONT ID="Void">void</FONT> lw() {
<A NAME="101"></A>        dataLock.writeLock().lock();
<A NAME="102"></A>    }
<A NAME="103"></A>
<A NAME="104"></A>    <FONT ID="FormalComment">/** Unlocks the data read lock */</FONT>
<A NAME="105"></A>    <FONT ID="Private">private</FONT> <FONT ID="Void">void</FONT> ur() {
<A NAME="106"></A>        dataLock.readLock().unlock();
<A NAME="107"></A>    }
<A NAME="108"></A>
<A NAME="109"></A>    <FONT ID="FormalComment">/** Unlocks the data write lock */</FONT>
<A NAME="110"></A>    <FONT ID="Private">private</FONT> <FONT ID="Void">void</FONT> uw() {
<A NAME="111"></A>        dataLock.writeLock().unlock();
<A NAME="112"></A>    }
<A NAME="113"></A>
<A NAME="114"></A>    <FONT ID="FormalComment">/** Locks the data read lock and result lock*/</FONT>
<A NAME="115"></A>    <FONT ID="Private">private</FONT> <FONT ID="Void">void</FONT> lrr() {
<A NAME="116"></A>        resultLock.lock();
<A NAME="117"></A>        dataLock.readLock().lock();
<A NAME="118"></A>    }
<A NAME="119"></A>
<A NAME="120"></A>    <FONT ID="FormalComment">/** Locks the data write lock and result lock*/</FONT>
<A NAME="121"></A>    <FONT ID="Private">private</FONT> <FONT ID="Void">void</FONT> lwr() {
<A NAME="122"></A>        resultLock.lock();
<A NAME="123"></A>        dataLock.writeLock().lock();
<A NAME="124"></A>    }
<A NAME="125"></A>
<A NAME="126"></A>    <FONT ID="FormalComment">/** Unlocks the data read lock and result lock*/</FONT>
<A NAME="127"></A>    <FONT ID="Private">private</FONT> <FONT ID="Void">void</FONT> urr() {
<A NAME="128"></A>        dataLock.readLock().unlock();
<A NAME="129"></A>        resultLock.unlock();
<A NAME="130"></A>    }
<A NAME="131"></A>
<A NAME="132"></A>    <FONT ID="FormalComment">/** Unlocks the data write lock and result lock*/</FONT>
<A NAME="133"></A>    <FONT ID="Private">private</FONT> <FONT ID="Void">void</FONT> uwr() {
<A NAME="134"></A>        dataLock.writeLock().unlock();
<A NAME="135"></A>        resultLock.unlock();
<A NAME="136"></A>    }
<A NAME="137"></A>
<A NAME="138"></A>    <FONT ID="FormalComment">/**
<A NAME="139"></A>     * Check, whether a user is among registered users of this server.
<A NAME="140"></A>     *
<A NAME="141"></A>     * @param   username    Username of the user to be checked
<A NAME="142"></A>     * @return          True when the user is registered, false otherwise
<A NAME="143"></A>     */</FONT>
<A NAME="144"></A>    <FONT ID="Public">public</FONT> <FONT ID="Boolean">boolean</FONT> isRegisteredUser(String username){
<A NAME="145"></A>        <FONT ID="SingleLineComment">//We just have to check the cache, because we keep it synchronized at all times
<A NAME="146"></A></FONT>        String escapedUsername = escapeSQL(username);
<A NAME="147"></A>
<A NAME="148"></A>        lr();
<A NAME="149"></A>        <FONT ID="Try">try</FONT> {
<A NAME="150"></A>            <FONT ID="Return">return</FONT> userCache.containsKey(escapedUsername);
<A NAME="151"></A>        } <FONT ID="Finally">finally</FONT> {
<A NAME="152"></A>            ur();
<A NAME="153"></A>        }
<A NAME="154"></A>    }
<A NAME="155"></A>
<A NAME="156"></A>    <FONT ID="FormalComment">/**
<A NAME="157"></A>     * Register a new user with the specified username.
<A NAME="158"></A>     * This method should only be called after isRegisteredUser method returns false.
<A NAME="159"></A>     *
<A NAME="160"></A>     * @param   username    Username of the newly registered user
<A NAME="161"></A>     * @throws  Exception       In case of DB access error
<A NAME="162"></A>     */</FONT>
<A NAME="163"></A>    <FONT ID="Public">public</FONT> <FONT ID="Void">void</FONT> registerUser(String username) <FONT ID="Throws">throws</FONT> Exception{
<A NAME="164"></A>        String escapedUsername = escapeSQL(username);
<A NAME="165"></A>
<A NAME="166"></A>        lwr();
<A NAME="167"></A>        <FONT ID="Try">try</FONT> {
<A NAME="168"></A>            <FONT ID="SingleLineComment">//First, insert the new user into table
<A NAME="169"></A></FONT>            statement.executeUpdate(<FONT ID="StringLiteral">"INSERT INTO users (`jabber_id`) VALUES ('"</FONT>+escapedUsername+<FONT ID="StringLiteral">"')"</FONT>);
<A NAME="170"></A>
<A NAME="171"></A>            <FONT ID="SingleLineComment">//Then retrieve the newly added value with its id and save it into cache
<A NAME="172"></A></FONT>            result = resultStatement.executeQuery(<FONT ID="StringLiteral">"SELECT jabber_id, id FROM users WHERE jabber_id = '"</FONT>+escapedUsername+<FONT ID="StringLiteral">"'"</FONT>);
<A NAME="173"></A>            <FONT ID="While">while</FONT> (result.next()){
<A NAME="174"></A>                userCache.put(result.getString(<FONT ID="StringLiteral">"jabber_id"</FONT>), <FONT ID="New">new</FONT> UserData(result.getLong(<FONT ID="StringLiteral">"id"</FONT>), <FONT ID="IntegerLiteral">0</FONT>));
<A NAME="175"></A>            }
<A NAME="176"></A>        } <FONT ID="Finally">finally</FONT> {
<A NAME="177"></A>            uwr();
<A NAME="178"></A>        }
<A NAME="179"></A>    }
<A NAME="180"></A>
<A NAME="181"></A>    <FONT ID="FormalComment">/**
<A NAME="182"></A>     * Unegister a user with the specified username.
<A NAME="183"></A>     * This method should only be called after isRegisteredUser method returns true.
<A NAME="184"></A>     *
<A NAME="185"></A>     * @param   username    Username of the user to be unregistered
<A NAME="186"></A>     * @throws  Exception       In case of DB access error
<A NAME="187"></A>     */</FONT>
<A NAME="188"></A>    <FONT ID="Public">public</FONT> <FONT ID="Void">void</FONT> unregisterUser(String username) <FONT ID="Throws">throws</FONT> Exception{
<A NAME="189"></A>        String escapedUsername = escapeSQL(username);
<A NAME="190"></A>
<A NAME="191"></A>        lw();
<A NAME="192"></A>        <FONT ID="Try">try</FONT> {
<A NAME="193"></A>            UserData ud = userCache.get(escapedUsername);
<A NAME="194"></A>
<A NAME="195"></A>            <FONT ID="SingleLineComment">//Disallow deletion of administrators
<A NAME="196"></A></FONT>            <FONT ID="If">if</FONT> (adminCache.containsKey(escapedUsername))
<A NAME="197"></A>                <FONT ID="Throw">throw</FONT> <FONT ID="New">new</FONT> Exception(<FONT ID="StringLiteral">"Cannot unregister a user that is an administrator"</FONT>);
<A NAME="198"></A>
<A NAME="199"></A>            <FONT ID="SingleLineComment">//Delete the user from the table
<A NAME="200"></A></FONT>            statement.executeUpdate(<FONT ID="StringLiteral">"DELETE FROM users WHERE jabber_id = '"</FONT>+escapedUsername+<FONT ID="StringLiteral">"'"</FONT>);
<A NAME="201"></A>
<A NAME="202"></A>            <FONT ID="SingleLineComment">//Delete the user from the cache
<A NAME="203"></A></FONT>            userCache.remove(escapedUsername);
<A NAME="204"></A>
<A NAME="205"></A>            <FONT ID="SingleLineComment">//Delete user's planned events
<A NAME="206"></A></FONT>            statement.executeUpdate(<FONT ID="StringLiteral">"DELETE FROM events WHERE user_or_group_id = '"</FONT>+ud.user_id+<FONT ID="StringLiteral">"'"</FONT>);
<A NAME="207"></A>
<A NAME="208"></A>            <FONT ID="SingleLineComment">//Delete user's subscription to groups
<A NAME="209"></A></FONT>            statement.executeUpdate(<FONT ID="StringLiteral">"DELETE FROM groupdata WHERE jabber_id = '"</FONT>+escapedUsername+<FONT ID="StringLiteral">"'"</FONT>);
<A NAME="210"></A>        } <FONT ID="Finally">finally</FONT> {
<A NAME="211"></A>            uw();
<A NAME="212"></A>        }
<A NAME="213"></A>    }
<A NAME="214"></A>
<A NAME="215"></A>    <FONT ID="FormalComment">/**
<A NAME="216"></A>     * Returns the string of all the user ids
<A NAME="217"></A>     *
<A NAME="218"></A>     * @return  The string of all the user ids
<A NAME="219"></A>     */</FONT>
<A NAME="220"></A>    <FONT ID="Public">public</FONT> String getUsers(){
<A NAME="221"></A>        String ret = <FONT ID="Null">null</FONT>;
<A NAME="222"></A>        <FONT ID="Try">try</FONT> {
<A NAME="223"></A>            ret = <FONT ID="StringLiteral">"Jabber id / difference of local time from server time / character encoding\n"</FONT>;
<A NAME="224"></A>
<A NAME="225"></A>            lr();
<A NAME="226"></A>
<A NAME="227"></A>            <FONT ID="SingleLineComment">//Get the set of all users from the user cache
<A NAME="228"></A></FONT>            Iterator it = userCache.entrySet().iterator();
<A NAME="229"></A>
<A NAME="230"></A>            <FONT ID="SingleLineComment">//Append their ids to the returned string
<A NAME="231"></A></FONT>            <FONT ID="While">while</FONT> (it.hasNext()){
<A NAME="232"></A>                Map.Entry&lt;String, UserData&gt; entry = (Map.Entry&lt;String, UserData&gt;)it.next();
<A NAME="233"></A>                ret += unescapeSQL(entry.getKey()) + <FONT ID="StringLiteral">" / "</FONT> + entry.getValue().gmt_offset/<FONT ID="IntegerLiteral">3600000</FONT> + <FONT ID="StringLiteral">":"</FONT>
<A NAME="234"></A>                + ((entry.getValue().gmt_offset/<FONT ID="IntegerLiteral">60000</FONT>%<FONT ID="IntegerLiteral">60</FONT> &lt;= <FONT ID="IntegerLiteral">9</FONT>)?<FONT ID="StringLiteral">"0"</FONT>:<FONT ID="StringLiteral">""</FONT>) + entry.getValue().gmt_offset/<FONT ID="IntegerLiteral">60000</FONT>%<FONT ID="IntegerLiteral">60</FONT> + <FONT ID="StringLiteral">"\n"</FONT>;
<A NAME="235"></A>            }
<A NAME="236"></A>
<A NAME="237"></A>            ur();
<A NAME="238"></A>
<A NAME="239"></A>        } <FONT ID="Catch">catch</FONT> (Exception e) {
<A NAME="240"></A>            System.err.println(<FONT ID="StringLiteral">"Map illegal state exception - this should not happen"</FONT>);
<A NAME="241"></A>        }
<A NAME="242"></A>        <FONT ID="Return">return</FONT> ret;
<A NAME="243"></A>    }
<A NAME="244"></A>
<A NAME="245"></A>    <FONT ID="FormalComment">/**
<A NAME="246"></A>     * Gets the offset of the given user to the server time
<A NAME="247"></A>     *
<A NAME="248"></A>     * @param   username    The Jabber id of the user
<A NAME="249"></A>     * @return          Offset from the server time in milliseconds or 0 if the user does not exist
<A NAME="250"></A>     */</FONT>
<A NAME="251"></A>    <FONT ID="Public">public</FONT> <FONT ID="Long">long</FONT> getUserTimeOffset(String username){
<A NAME="252"></A>        String escapedUsername = escapeSQL(username);
<A NAME="253"></A>
<A NAME="254"></A>        lr();
<A NAME="255"></A>        UserData ud = userCache.get(escapedUsername);
<A NAME="256"></A>        ur();
<A NAME="257"></A>
<A NAME="258"></A>        <FONT ID="If">if</FONT> (ud == <FONT ID="Null">null</FONT>) <FONT ID="Return">return</FONT> <FONT ID="IntegerLiteral">0</FONT>;
<A NAME="259"></A>        <FONT ID="Else">else</FONT> <FONT ID="Return">return</FONT> ud.gmt_offset;
<A NAME="260"></A>    }
<A NAME="261"></A>
<A NAME="262"></A>    <FONT ID="FormalComment">/**
<A NAME="263"></A>     * Sets the time offset of a user to the given value
<A NAME="264"></A>     *
<A NAME="265"></A>     * @param   username    The Jabber id of the user
<A NAME="266"></A>     * @param   newOffset       The new offset of the user from the server (in milliseconds)
<A NAME="267"></A>     * @throws  Exception   If the username is not in the DB or if the DB cannot be updated
<A NAME="268"></A>     */</FONT>
<A NAME="269"></A>    <FONT ID="Public">public</FONT> <FONT ID="Void">void</FONT> setUserTimeOffset(String username, <FONT ID="Long">long</FONT> newOffset) <FONT ID="Throws">throws</FONT> Exception{
<A NAME="270"></A>        String escapedUsername = escapeSQL(username);
<A NAME="271"></A>
<A NAME="272"></A>        lw();
<A NAME="273"></A>        <FONT ID="Try">try</FONT> {
<A NAME="274"></A>            UserData ud = userCache.get(escapedUsername);
<A NAME="275"></A>
<A NAME="276"></A>            <FONT ID="If">if</FONT> (ud == <FONT ID="Null">null</FONT>) <FONT ID="Throw">throw</FONT> <FONT ID="New">new</FONT> Exception(<FONT ID="StringLiteral">"Invalid username"</FONT>);
<A NAME="277"></A>
<A NAME="278"></A>            <FONT ID="SingleLineComment">//Update the DB
<A NAME="279"></A></FONT>            statement.executeUpdate(<FONT ID="StringLiteral">"UPDATE users SET gmt_offset="</FONT>+newOffset+<FONT ID="StringLiteral">" WHERE id="</FONT>+ud.user_id);
<A NAME="280"></A>
<A NAME="281"></A>            <FONT ID="SingleLineComment">//Update the data in cache
<A NAME="282"></A></FONT>            ud.gmt_offset = newOffset;
<A NAME="283"></A>        } <FONT ID="Finally">finally</FONT> {
<A NAME="284"></A>            uw();
<A NAME="285"></A>        }
<A NAME="286"></A>    }
<A NAME="287"></A>
<A NAME="288"></A>    <FONT ID="SingleLineComment">// Admin privileges codes:
<A NAME="289"></A></FONT>    <FONT ID="SingleLineComment">// modify admins - 1
<A NAME="290"></A></FONT>    <FONT ID="SingleLineComment">// modify users - 2
<A NAME="291"></A></FONT>    <FONT ID="SingleLineComment">// modify groups - 4
<A NAME="292"></A></FONT>    <FONT ID="SingleLineComment">// modify settings - 8
<A NAME="293"></A></FONT>
<A NAME="294"></A>    <FONT ID="FormalComment">/**
<A NAME="295"></A>     * Check, whether the user is an admin that can modify administrators and their rights
<A NAME="296"></A>     *
<A NAME="297"></A>     * @param   username    The user in question
<A NAME="298"></A>     * @return                  True if the admin can modify other admins, false otherwise
<A NAME="299"></A>     */</FONT>
<A NAME="300"></A>    <FONT ID="Public">public</FONT> <FONT ID="Boolean">boolean</FONT> adminCanModifyAdmins(String username){
<A NAME="301"></A>        String escapedUsername = escapeSQL(username);
<A NAME="302"></A>
<A NAME="303"></A>        lr();
<A NAME="304"></A>        Integer privs = adminCache.get(escapedUsername);
<A NAME="305"></A>        ur();
<A NAME="306"></A>
<A NAME="307"></A>        <FONT ID="If">if</FONT> (privs == <FONT ID="Null">null</FONT>) <FONT ID="Return">return</FONT> <FONT ID="False">false</FONT>;
<A NAME="308"></A>        <FONT ID="If">if</FONT> ((privs.intValue() &amp; <FONT ID="IntegerLiteral">1</FONT>) == <FONT ID="IntegerLiteral">1</FONT>) <FONT ID="Return">return</FONT> <FONT ID="True">true</FONT>;
<A NAME="309"></A>        <FONT ID="Else">else</FONT> <FONT ID="Return">return</FONT> <FONT ID="False">false</FONT>;
<A NAME="310"></A>    }
<A NAME="311"></A>
<A NAME="312"></A>    <FONT ID="FormalComment">/**
<A NAME="313"></A>     * Check, whether the user is an admin that can modify registration of users
<A NAME="314"></A>     *
<A NAME="315"></A>     * @param   username    The user in question
<A NAME="316"></A>     * @return                  True if the admin can modify users, false otherwise
<A NAME="317"></A>     */</FONT>
<A NAME="318"></A>    <FONT ID="Public">public</FONT> <FONT ID="Boolean">boolean</FONT> adminCanModifyUsers(String username){
<A NAME="319"></A>        String escapedUsername = escapeSQL(username);
<A NAME="320"></A>
<A NAME="321"></A>        lr();
<A NAME="322"></A>        Integer privs = adminCache.get(escapedUsername);
<A NAME="323"></A>        ur();
<A NAME="324"></A>
<A NAME="325"></A>        <FONT ID="If">if</FONT> (privs == <FONT ID="Null">null</FONT>) <FONT ID="Return">return</FONT> <FONT ID="False">false</FONT>;
<A NAME="326"></A>        <FONT ID="If">if</FONT> ((privs.intValue() &amp; <FONT ID="IntegerLiteral">2</FONT>) == <FONT ID="IntegerLiteral">2</FONT>) <FONT ID="Return">return</FONT> <FONT ID="True">true</FONT>;
<A NAME="327"></A>        <FONT ID="Else">else</FONT> <FONT ID="Return">return</FONT> <FONT ID="False">false</FONT>;
<A NAME="328"></A>    }
<A NAME="329"></A>
<A NAME="330"></A>    <FONT ID="FormalComment">/**
<A NAME="331"></A>     * Check, whether the user is an admin that can modify and view groups
<A NAME="332"></A>     *
<A NAME="333"></A>     * @param   username    The user in question
<A NAME="334"></A>     * @return                  True if the admin can modify groups, false otherwise
<A NAME="335"></A>     */</FONT>
<A NAME="336"></A>    <FONT ID="Public">public</FONT> <FONT ID="Boolean">boolean</FONT> adminCanModifyGroups(String username){
<A NAME="337"></A>        String escapedUsername = escapeSQL(username);
<A NAME="338"></A>
<A NAME="339"></A>        lr();
<A NAME="340"></A>        Integer privs = adminCache.get(escapedUsername);
<A NAME="341"></A>        ur();
<A NAME="342"></A>
<A NAME="343"></A>        <FONT ID="If">if</FONT> (privs == <FONT ID="Null">null</FONT>) <FONT ID="Return">return</FONT> <FONT ID="False">false</FONT>;
<A NAME="344"></A>        <FONT ID="If">if</FONT> ((privs.intValue() &amp; <FONT ID="IntegerLiteral">4</FONT>) == <FONT ID="IntegerLiteral">4</FONT>) <FONT ID="Return">return</FONT> <FONT ID="True">true</FONT>;
<A NAME="345"></A>        <FONT ID="Else">else</FONT> <FONT ID="Return">return</FONT> <FONT ID="False">false</FONT>;
<A NAME="346"></A>    }
<A NAME="347"></A>
<A NAME="348"></A>    <FONT ID="FormalComment">/**
<A NAME="349"></A>     * Sets the privileges for the given user.
<A NAME="350"></A>     *
<A NAME="351"></A>     * @return  The string with message informing about the success
<A NAME="352"></A>     * @param   username        The JID of the user in question
<A NAME="353"></A>     * @param   newPrivileges   The new privileges that should be set for the user
<A NAME="354"></A>     * @throws  Exception       If the user does not exist or in case of database error or incorrect parameters
<A NAME="355"></A>     */</FONT>
<A NAME="356"></A>    <FONT ID="Public">public</FONT> String setAdminPrivileges(String username, <FONT ID="Int">int</FONT> newPrivileges) <FONT ID="Throws">throws</FONT> Exception{
<A NAME="357"></A>        String escapedUsername = escapeSQL(username);
<A NAME="358"></A>
<A NAME="359"></A>        lwr();
<A NAME="360"></A>        <FONT ID="Try">try</FONT> {
<A NAME="361"></A>
<A NAME="362"></A>        <FONT ID="SingleLineComment">//Throw an exception if the user does not exist
<A NAME="363"></A></FONT>        result = resultStatement.executeQuery(<FONT ID="StringLiteral">"SELECT * FROM users WHERE jabber_id='"</FONT>+escapedUsername+<FONT ID="StringLiteral">"'"</FONT>);
<A NAME="364"></A>        <FONT ID="If">if</FONT> (!result.next()) <FONT ID="Throw">throw</FONT> <FONT ID="New">new</FONT> Exception(<FONT ID="StringLiteral">"Could not set admin privileges - user does not exist"</FONT>);
<A NAME="365"></A>
<A NAME="366"></A>        <FONT ID="SingleLineComment">//Remove all admin privileges from the user
<A NAME="367"></A></FONT>        <FONT ID="If">if</FONT> (newPrivileges == <FONT ID="IntegerLiteral">0</FONT>) {
<A NAME="368"></A>            statement.executeUpdate(<FONT ID="StringLiteral">"DELETE FROM admins WHERE jabber_id='"</FONT>+escapedUsername+<FONT ID="StringLiteral">"'"</FONT>);
<A NAME="369"></A>            adminCache.remove(escapedUsername);
<A NAME="370"></A>            <FONT ID="Return">return</FONT> <FONT ID="StringLiteral">"Removed all administrator privileges from user "</FONT>+username;
<A NAME="371"></A>        <FONT ID="SingleLineComment">//Change or newly set privileges of the user
<A NAME="372"></A></FONT>        } <FONT ID="Else">else</FONT> <FONT ID="If">if</FONT> (newPrivileges &gt; <FONT ID="IntegerLiteral">0</FONT> &amp;&amp; newPrivileges &lt; <FONT ID="IntegerLiteral">16</FONT>) {
<A NAME="373"></A>            statement.executeUpdate(<FONT ID="StringLiteral">"DELETE FROM admins WHERE jabber_id='"</FONT>+escapedUsername+<FONT ID="StringLiteral">"'"</FONT>);
<A NAME="374"></A>            statement.executeUpdate(<FONT ID="StringLiteral">"INSERT INTO admins (`jabber_id`,`privileges`) VALUES ('"</FONT>+escapedUsername+<FONT ID="StringLiteral">"',"</FONT>+newPrivileges+<FONT ID="StringLiteral">")"</FONT>);
<A NAME="375"></A>            adminCache.put(escapedUsername, newPrivileges);
<A NAME="376"></A>            <FONT ID="Return">return</FONT> <FONT ID="StringLiteral">"Modified administrator privileges of user "</FONT>+username;
<A NAME="377"></A>        } <FONT ID="Else">else</FONT> {
<A NAME="378"></A>            <FONT ID="Throw">throw</FONT> <FONT ID="New">new</FONT> Exception(<FONT ID="StringLiteral">"Could not set admin privileges - number should be between 0 and 15"</FONT>);
<A NAME="379"></A>        }
<A NAME="380"></A>
<A NAME="381"></A>        } <FONT ID="Finally">finally</FONT> {
<A NAME="382"></A>            uwr();
<A NAME="383"></A>        }
<A NAME="384"></A>    }
<A NAME="385"></A>
<A NAME="386"></A>    <FONT ID="FormalComment">/**
<A NAME="387"></A>     * Returns the string of all the admins and their privileges
<A NAME="388"></A>     *
<A NAME="389"></A>     * @return  The string of all the admins
<A NAME="390"></A>     * @throws  Exception   In case of database access error
<A NAME="391"></A>     */</FONT>
<A NAME="392"></A>    <FONT ID="Public">public</FONT> String getAdmins() <FONT ID="Throws">throws</FONT> Exception{
<A NAME="393"></A>        String ret = <FONT ID="StringLiteral">""</FONT>;
<A NAME="394"></A>
<A NAME="395"></A>        lr();
<A NAME="396"></A>        <FONT ID="Try">try</FONT> {
<A NAME="397"></A>
<A NAME="398"></A>        <FONT ID="SingleLineComment">//Get the set of all admins from the cache
<A NAME="399"></A></FONT>        Iterator it = adminCache.entrySet().iterator();
<A NAME="400"></A>
<A NAME="401"></A>        <FONT ID="SingleLineComment">//Append their ids and privileges to the returned string
<A NAME="402"></A></FONT>        <FONT ID="While">while</FONT> (it.hasNext()){
<A NAME="403"></A>            Map.Entry&lt;String, Integer&gt; adminEntry = (Map.Entry&lt;String, Integer&gt;)it.next();
<A NAME="404"></A>            ret += unescapeSQL(adminEntry.getKey()) + <FONT ID="StringLiteral">", privileges: "</FONT>;
<A NAME="405"></A>            <FONT ID="Int">int</FONT> privs = adminEntry.getValue().intValue();
<A NAME="406"></A>            ret += privs;
<A NAME="407"></A>            <FONT ID="For">for</FONT> (<FONT ID="Int">int</FONT> i = <FONT ID="IntegerLiteral">1</FONT>; i &lt;= <FONT ID="IntegerLiteral">8</FONT>; i &lt;&lt;= <FONT ID="IntegerLiteral">1</FONT>){
<A NAME="408"></A>                <FONT ID="If">if</FONT> ((privs &amp; i) == i)
<A NAME="409"></A>                    <FONT ID="Switch">switch</FONT> (i) {
<A NAME="410"></A>                        <FONT ID="Case">case</FONT> <FONT ID="IntegerLiteral">1</FONT>:
<A NAME="411"></A>                            ret += <FONT ID="StringLiteral">", modify admins"</FONT>;
<A NAME="412"></A>                        <FONT ID="Break">break</FONT>;
<A NAME="413"></A>                        <FONT ID="Case">case</FONT> <FONT ID="IntegerLiteral">2</FONT>:
<A NAME="414"></A>                            ret += <FONT ID="StringLiteral">", modify users"</FONT>;
<A NAME="415"></A>                        <FONT ID="Break">break</FONT>;
<A NAME="416"></A>                        <FONT ID="Case">case</FONT> <FONT ID="IntegerLiteral">4</FONT>:
<A NAME="417"></A>                            ret += <FONT ID="StringLiteral">", modify groups"</FONT>;
<A NAME="418"></A>                        <FONT ID="Break">break</FONT>;
<A NAME="419"></A>                        <FONT ID="Case">case</FONT> <FONT ID="IntegerLiteral">8</FONT>:
<A NAME="420"></A>                            ret += <FONT ID="StringLiteral">", modify settings"</FONT>;
<A NAME="421"></A>                        <FONT ID="Break">break</FONT>;
<A NAME="422"></A>                    }
<A NAME="423"></A>            }
<A NAME="424"></A>            ret += <FONT ID="StringLiteral">"\n"</FONT>;
<A NAME="425"></A>        }
<A NAME="426"></A>
<A NAME="427"></A>        } <FONT ID="Finally">finally</FONT> {
<A NAME="428"></A>            ur();
<A NAME="429"></A>        }
<A NAME="430"></A>
<A NAME="431"></A>        <FONT ID="Return">return</FONT> ret;
<A NAME="432"></A>    }
<A NAME="433"></A>
<A NAME="434"></A>    <FONT ID="FormalComment">/**
<A NAME="435"></A>     * Creates a group with given name and description
<A NAME="436"></A>     * 
<A NAME="437"></A>     * @param   name        Name of the group that will be created
<A NAME="438"></A>     * @param   description String with description of the new group
<A NAME="439"></A>     * @return                  Message with information about success (if successful)
<A NAME="440"></A>     * @throws  Exception       If the group cannot be added or the database cannot be accessed
<A NAME="441"></A>     */</FONT>
<A NAME="442"></A>    <FONT ID="Public">public</FONT> String addGroup(String name, String description) <FONT ID="Throws">throws</FONT> Exception{
<A NAME="443"></A>        String escapedName = escapeSQL(name);
<A NAME="444"></A>
<A NAME="445"></A>        lwr();
<A NAME="446"></A>        <FONT ID="Try">try</FONT> {
<A NAME="447"></A>
<A NAME="448"></A>        result = resultStatement.executeQuery(<FONT ID="StringLiteral">"SELECT id FROM groups WHERE "</FONT>
<A NAME="449"></A>                                      + <FONT ID="StringLiteral">"group_name ='"</FONT>+escapedName+<FONT ID="StringLiteral">"'"</FONT>);
<A NAME="450"></A>        <FONT ID="SingleLineComment">//The group with given name already exists
<A NAME="451"></A></FONT>        <FONT ID="If">if</FONT> (result.next()){
<A NAME="452"></A>            <FONT ID="Throw">throw</FONT> <FONT ID="New">new</FONT> Exception(<FONT ID="StringLiteral">"Could not create new group. Group \""</FONT>+name+<FONT ID="StringLiteral">"\" already exists with ID "</FONT>
<A NAME="453"></A>            + result.getInt(<FONT ID="IntegerLiteral">1</FONT>));
<A NAME="454"></A>        }
<A NAME="455"></A>
<A NAME="456"></A>        statement.executeUpdate(<FONT ID="StringLiteral">"INSERT INTO groups (`group_name`,`description`) "</FONT>
<A NAME="457"></A>                             + <FONT ID="StringLiteral">"VALUES ('"</FONT>+escapedName+<FONT ID="StringLiteral">"','"</FONT>+escapeSQL(description)+<FONT ID="StringLiteral">"')"</FONT>);
<A NAME="458"></A>        } <FONT ID="Finally">finally</FONT> {
<A NAME="459"></A>            uwr();
<A NAME="460"></A>        }
<A NAME="461"></A>
<A NAME="462"></A>        <FONT ID="Return">return</FONT> <FONT ID="StringLiteral">"Successfully created new group"</FONT>;
<A NAME="463"></A>    }
<A NAME="464"></A>
<A NAME="465"></A>    <FONT ID="FormalComment">/**
<A NAME="466"></A>     * Change the given group's name and/or description
<A NAME="467"></A>     *
<A NAME="468"></A>     * @param   groupID         ID number of the group that should be modified
<A NAME="469"></A>     * @param   newDescription  The new description of the group (can be null to keep the old description)
<A NAME="470"></A>     * @param   newName         The new name of the group (can be null to keep the old name)
<A NAME="471"></A>     * @param   self_subscription   The new state for group self-subscription: 0 = don't allow; 1 = allow; other value = don't modify
<A NAME="472"></A>     *                              value of this flag
<A NAME="473"></A>     * @return                  String informing about success if successful
<A NAME="474"></A>     * @throws  Exception       If the group cannot be modified or DB cannot be accessed
<A NAME="475"></A>     */</FONT>
<A NAME="476"></A>    <FONT ID="Public">public</FONT> String modifyGroup(<FONT ID="Long">long</FONT> groupID, String newDescription, String newName, <FONT ID="Int">int</FONT> self_subscription) <FONT ID="Throws">throws</FONT> Exception{
<A NAME="477"></A>        String escapedDescription = <FONT ID="Null">null</FONT>;
<A NAME="478"></A>        <FONT ID="If">if</FONT> (newDescription != <FONT ID="Null">null</FONT>) escapedDescription = escapeSQL(newDescription);
<A NAME="479"></A>        String escapedName = <FONT ID="Null">null</FONT>;
<A NAME="480"></A>        <FONT ID="If">if</FONT> (newName != <FONT ID="Null">null</FONT>) escapedName = escapeSQL(newName);
<A NAME="481"></A>
<A NAME="482"></A>        <FONT ID="Boolean">boolean</FONT> firstSet = <FONT ID="True">true</FONT>;
<A NAME="483"></A>        String command = <FONT ID="StringLiteral">"UPDATE groups SET "</FONT>;
<A NAME="484"></A>        <FONT ID="If">if</FONT> (escapedName != <FONT ID="Null">null</FONT>) {
<A NAME="485"></A>            command += <FONT ID="StringLiteral">"group_name='"</FONT>+escapedName+<FONT ID="StringLiteral">"' "</FONT>;
<A NAME="486"></A>            firstSet = <FONT ID="False">false</FONT>;
<A NAME="487"></A>        }
<A NAME="488"></A>        <FONT ID="If">if</FONT> (escapedDescription != <FONT ID="Null">null</FONT>) {
<A NAME="489"></A>            <FONT ID="If">if</FONT> (!firstSet) command += <FONT ID="StringLiteral">", "</FONT>;
<A NAME="490"></A>            command += <FONT ID="StringLiteral">"description='"</FONT>+escapedDescription+<FONT ID="StringLiteral">"' "</FONT>;
<A NAME="491"></A>            firstSet = <FONT ID="False">false</FONT>;
<A NAME="492"></A>        }
<A NAME="493"></A>        <FONT ID="If">if</FONT> (self_subscription == <FONT ID="IntegerLiteral">0</FONT>) {
<A NAME="494"></A>            <FONT ID="If">if</FONT> (!firstSet) command += <FONT ID="StringLiteral">", "</FONT>;
<A NAME="495"></A>            command += <FONT ID="StringLiteral">"self_subscription='0' "</FONT>;
<A NAME="496"></A>            firstSet = <FONT ID="False">false</FONT>;
<A NAME="497"></A>        }
<A NAME="498"></A>        <FONT ID="If">if</FONT> (self_subscription == <FONT ID="IntegerLiteral">1</FONT>) {
<A NAME="499"></A>            <FONT ID="If">if</FONT> (!firstSet) command += <FONT ID="StringLiteral">", "</FONT>;
<A NAME="500"></A>            command += <FONT ID="StringLiteral">"self_subscription='1' "</FONT>;
<A NAME="501"></A>            firstSet = <FONT ID="False">false</FONT>;
<A NAME="502"></A>        }
<A NAME="503"></A>        command += <FONT ID="StringLiteral">"WHERE id="</FONT>+groupID;
<A NAME="504"></A>
<A NAME="505"></A>        lw();
<A NAME="506"></A>        <FONT ID="Try">try</FONT> {
<A NAME="507"></A>        statement.executeUpdate(command);
<A NAME="508"></A>        <FONT ID="If">if</FONT> (statement.getUpdateCount() != <FONT ID="IntegerLiteral">1</FONT>)
<A NAME="509"></A>            <FONT ID="Throw">throw</FONT> <FONT ID="New">new</FONT> Exception(<FONT ID="StringLiteral">"Could not modify group. No group with id "</FONT>+groupID+<FONT ID="StringLiteral">" exists."</FONT>);
<A NAME="510"></A>        } <FONT ID="Finally">finally</FONT> {
<A NAME="511"></A>            uw();
<A NAME="512"></A>        }
<A NAME="513"></A>
<A NAME="514"></A>        <FONT ID="Return">return</FONT> <FONT ID="StringLiteral">"Successfully modified group "</FONT>+groupID;
<A NAME="515"></A>    }
<A NAME="516"></A>
<A NAME="517"></A>    <FONT ID="FormalComment">/**
<A NAME="518"></A>     * Remove the whole group with user subscriptions and planned events
<A NAME="519"></A>     *
<A NAME="520"></A>     * @param   groupID     ID number of the group to be deleted
<A NAME="521"></A>     * @throws  Exception   In case of incorrect group ID or database error
<A NAME="522"></A>     * @return              String with the information about the operation
<A NAME="523"></A>     */</FONT>
<A NAME="524"></A>    <FONT ID="Public">public</FONT> String removeGroup(<FONT ID="Long">long</FONT> groupID) <FONT ID="Throws">throws</FONT> Exception{
<A NAME="525"></A>        lwr();
<A NAME="526"></A>        <FONT ID="Try">try</FONT> {
<A NAME="527"></A>
<A NAME="528"></A>        <FONT ID="SingleLineComment">//First check, whether the group exists
<A NAME="529"></A></FONT>        result = resultStatement.executeQuery(<FONT ID="StringLiteral">"SELECT * FROM groups WHERE id="</FONT>+groupID);
<A NAME="530"></A>        <FONT ID="If">if</FONT> (!result.next())
<A NAME="531"></A>            <FONT ID="Throw">throw</FONT> <FONT ID="New">new</FONT> Exception(<FONT ID="StringLiteral">"Could not remove group. No group with id "</FONT>+groupID+<FONT ID="StringLiteral">" exists."</FONT>);
<A NAME="532"></A>
<A NAME="533"></A>        <FONT ID="SingleLineComment">//Remove group events
<A NAME="534"></A></FONT>        statement.executeUpdate(<FONT ID="StringLiteral">"DELETE FROM events WHERE groupevent = 1 AND user_or_group_id = '"</FONT>+groupID+<FONT ID="StringLiteral">"'"</FONT>);
<A NAME="535"></A>        <FONT ID="SingleLineComment">//Remove group subscriptions
<A NAME="536"></A></FONT>        statement.executeUpdate(<FONT ID="StringLiteral">"DELETE FROM groupdata WHERE groupid = '"</FONT>+groupID+<FONT ID="StringLiteral">"'"</FONT>);
<A NAME="537"></A>        <FONT ID="SingleLineComment">//Remove the group
<A NAME="538"></A></FONT>        statement.executeUpdate(<FONT ID="StringLiteral">"DELETE FROM groups WHERE id = '"</FONT>+groupID+<FONT ID="StringLiteral">"'"</FONT>);
<A NAME="539"></A>
<A NAME="540"></A>        } <FONT ID="Finally">finally</FONT> {
<A NAME="541"></A>            uwr();
<A NAME="542"></A>        }
<A NAME="543"></A>
<A NAME="544"></A>        <FONT ID="Return">return</FONT> <FONT ID="StringLiteral">"Successfully removed group with ID "</FONT>+groupID;
<A NAME="545"></A>    }
<A NAME="546"></A>
<A NAME="547"></A>    <FONT ID="FormalComment">/**
<A NAME="548"></A>     * List all users subscribed to the given group
<A NAME="549"></A>     *
<A NAME="550"></A>     * @param   groupID     ID number of the group, whose users are to be listed
<A NAME="551"></A>     * @throws  Exception   In case of an incorrect group ID or database error
<A NAME="552"></A>     * @return              String with the list of all group users
<A NAME="553"></A>     */</FONT>
<A NAME="554"></A>    <FONT ID="Public">public</FONT> String listGroupUsers(<FONT ID="Long">long</FONT> groupID) <FONT ID="Throws">throws</FONT> Exception{
<A NAME="555"></A>        String ret;
<A NAME="556"></A>
<A NAME="557"></A>        lrr();
<A NAME="558"></A>        <FONT ID="Try">try</FONT> {
<A NAME="559"></A>
<A NAME="560"></A>        <FONT ID="SingleLineComment">//First check, whether the group exists at all
<A NAME="561"></A></FONT>        result = resultStatement.executeQuery(<FONT ID="StringLiteral">"SELECT * FROM groups WHERE id="</FONT>+groupID);
<A NAME="562"></A>        <FONT ID="If">if</FONT> (!result.next())
<A NAME="563"></A>            <FONT ID="Throw">throw</FONT> <FONT ID="New">new</FONT> Exception(<FONT ID="StringLiteral">"Could not list users of group. No group with id "</FONT>+groupID+<FONT ID="StringLiteral">" exists."</FONT>);
<A NAME="564"></A>
<A NAME="565"></A>        <FONT ID="SingleLineComment">//List users
<A NAME="566"></A></FONT>        result = resultStatement.executeQuery(<FONT ID="StringLiteral">"SELECT jabber_id, privileges FROM groupdata WHERE groupid = '"</FONT>+groupID+<FONT ID="StringLiteral">"'"</FONT>);
<A NAME="567"></A>        ret = <FONT ID="StringLiteral">"Jabber ID / User privileges for the group (1 - modify, 2 - list, 4 - plan)\n"</FONT>;
<A NAME="568"></A>        <FONT ID="While">while</FONT> (result.next()){
<A NAME="569"></A>            ret += result.getString(<FONT ID="StringLiteral">"jabber_id"</FONT>) + <FONT ID="StringLiteral">" / "</FONT> + result.getString(<FONT ID="StringLiteral">"privileges"</FONT>) + <FONT ID="StringLiteral">"\n"</FONT>;
<A NAME="570"></A>        }
<A NAME="571"></A>
<A NAME="572"></A>        } <FONT ID="Catch">catch</FONT> (Exception e) {
<A NAME="573"></A>            ret = e.getMessage();
<A NAME="574"></A>        } <FONT ID="Finally">finally</FONT> {
<A NAME="575"></A>            urr();
<A NAME="576"></A>        }
<A NAME="577"></A>
<A NAME="578"></A>        <FONT ID="Return">return</FONT> ret;
<A NAME="579"></A>    }
<A NAME="580"></A>
<A NAME="581"></A>    <FONT ID="FormalComment">/**
<A NAME="582"></A>     * Subscribes the given user to the group.
<A NAME="583"></A>     * This user must, however, be registered with this jjsched server
<A NAME="584"></A>     *
<A NAME="585"></A>     * @param   groupID     ID number of the group to which the user should be subscribed
<A NAME="586"></A>     * @param   user        Jabber ID of the user
<A NAME="587"></A>     * @throws  Exception   If the user is not registered with the server, the group does not exist or in case of DB error
<A NAME="588"></A>     * @return              Information string about the subscription
<A NAME="589"></A>     */</FONT>
<A NAME="590"></A>    <FONT ID="Public">public</FONT> String subscribeToGroup(<FONT ID="Long">long</FONT> groupID, String user) <FONT ID="Throws">throws</FONT> Exception{
<A NAME="591"></A>        String escapedUser = escapeSQL(user);
<A NAME="592"></A>
<A NAME="593"></A>        lwr();
<A NAME="594"></A>        <FONT ID="Try">try</FONT> {
<A NAME="595"></A>
<A NAME="596"></A>        <FONT ID="SingleLineComment">//Check if the user is registered
<A NAME="597"></A></FONT>        result = resultStatement.executeQuery(<FONT ID="StringLiteral">"SELECT * FROM users WHERE jabber_id='"</FONT>+escapedUser+<FONT ID="StringLiteral">"'"</FONT>);
<A NAME="598"></A>        <FONT ID="If">if</FONT> (!result.next())
<A NAME="599"></A>            <FONT ID="Throw">throw</FONT> <FONT ID="New">new</FONT> Exception(<FONT ID="StringLiteral">"Could not subscribe user to group. User is not registered."</FONT>);
<A NAME="600"></A>
<A NAME="601"></A>        <FONT ID="SingleLineComment">//Check if the group exists
<A NAME="602"></A></FONT>        result = resultStatement.executeQuery(<FONT ID="StringLiteral">"SELECT * FROM groups WHERE id="</FONT>+groupID);
<A NAME="603"></A>        <FONT ID="If">if</FONT> (!result.next())
<A NAME="604"></A>            <FONT ID="Throw">throw</FONT> <FONT ID="New">new</FONT> Exception(<FONT ID="StringLiteral">"Could not subscribe user to group. Group does not exist."</FONT>);
<A NAME="605"></A>
<A NAME="606"></A>        statement.executeUpdate(<FONT ID="StringLiteral">"INSERT INTO groupdata (`groupid`, `jabber_id`, `privileges`) VALUES "</FONT>
<A NAME="607"></A>                + <FONT ID="StringLiteral">"('"</FONT>+groupID+<FONT ID="StringLiteral">"', '"</FONT>+escapedUser+<FONT ID="StringLiteral">"', '0')"</FONT>);
<A NAME="608"></A>        } <FONT ID="Finally">finally</FONT> {
<A NAME="609"></A>            uwr();
<A NAME="610"></A>        }
<A NAME="611"></A>
<A NAME="612"></A>        <FONT ID="Return">return</FONT> <FONT ID="StringLiteral">"User "</FONT>+user+<FONT ID="StringLiteral">" subscribed to group number "</FONT>+groupID;
<A NAME="613"></A>    }
<A NAME="614"></A>
<A NAME="615"></A>    <FONT ID="FormalComment">/**
<A NAME="616"></A>     * Unsubscribes the given user from the group.
<A NAME="617"></A>     *
<A NAME="618"></A>     * @param   groupID     ID number of the group from which the user should be unsubscribed
<A NAME="619"></A>     * @param   user        Jabber ID of the user
<A NAME="620"></A>     * @throws  Exception   If the user is not subscribed to the group, if the group does not exist or in case of DB error
<A NAME="621"></A>     * @return              Information string about the unsubscription
<A NAME="622"></A>     */</FONT>
<A NAME="623"></A>    <FONT ID="Public">public</FONT> String unsubscribeFromGroup(<FONT ID="Long">long</FONT> groupID, String user) <FONT ID="Throws">throws</FONT> Exception{
<A NAME="624"></A>        String escapedUser = escapeSQL(user);
<A NAME="625"></A>
<A NAME="626"></A>        lwr();
<A NAME="627"></A>        <FONT ID="Try">try</FONT>{
<A NAME="628"></A>
<A NAME="629"></A>        <FONT ID="SingleLineComment">//Check if the group exists
<A NAME="630"></A></FONT>        result = resultStatement.executeQuery(<FONT ID="StringLiteral">"SELECT * FROM groups WHERE id="</FONT>+groupID);
<A NAME="631"></A>        <FONT ID="If">if</FONT> (!result.next())
<A NAME="632"></A>            <FONT ID="Throw">throw</FONT> <FONT ID="New">new</FONT> Exception(<FONT ID="StringLiteral">"Could not unsubscribe user from group. Group does not exist."</FONT>);
<A NAME="633"></A>
<A NAME="634"></A>        <FONT ID="SingleLineComment">//Check if the user is in the group
<A NAME="635"></A></FONT>        result = resultStatement.executeQuery(<FONT ID="StringLiteral">"SELECT * FROM groupdata WHERE jabber_id='"</FONT>+escapedUser+<FONT ID="StringLiteral">"'"</FONT>);
<A NAME="636"></A>        <FONT ID="If">if</FONT> (!result.next())
<A NAME="637"></A>            <FONT ID="Throw">throw</FONT> <FONT ID="New">new</FONT> Exception(<FONT ID="StringLiteral">"Could not unsubscribe user from group. User is not subscribed."</FONT>);
<A NAME="638"></A>
<A NAME="639"></A>        statement.executeUpdate(<FONT ID="StringLiteral">"DELETE FROM groupdata WHERE groupid="</FONT>+groupID+<FONT ID="StringLiteral">" AND "</FONT>
<A NAME="640"></A>                + <FONT ID="StringLiteral">" jabber_id='"</FONT>+escapedUser+<FONT ID="StringLiteral">"'"</FONT>);
<A NAME="641"></A>
<A NAME="642"></A>        } <FONT ID="Finally">finally</FONT> {
<A NAME="643"></A>            uwr();
<A NAME="644"></A>        }
<A NAME="645"></A>
<A NAME="646"></A>        <FONT ID="Return">return</FONT> <FONT ID="StringLiteral">"User "</FONT>+user+<FONT ID="StringLiteral">" unsubscribed from group number "</FONT>+groupID;
<A NAME="647"></A>    }
<A NAME="648"></A>
<A NAME="649"></A>    <FONT ID="FormalComment">/**
<A NAME="650"></A>     * Sets the privileges of the given user for modifying the given group.
<A NAME="651"></A>     * The privileges are a combination of 1 - user can tamper with the group,
<A NAME="652"></A>     * 2 - user can view group information, 4 - user can plan group events
<A NAME="653"></A>     *
<A NAME="654"></A>     * @param   groupID ID number of the group in question
<A NAME="655"></A>     * @param   user    The Jabber ID of the user whose privileges should be modified
<A NAME="656"></A>     * @param   newPrivileges   The new value of privileges
<A NAME="657"></A>     * @return          String with information about success
<A NAME="658"></A>     * @throws  Exception   In case of DB access error
<A NAME="659"></A>     */</FONT>
<A NAME="660"></A>    <FONT ID="Public">public</FONT> String setUserGroupPrivileges(<FONT ID="Long">long</FONT> groupID, String user, <FONT ID="Int">int</FONT> newPrivileges) <FONT ID="Throws">throws</FONT> Exception{
<A NAME="661"></A>        String escapedUser = escapeSQL(user);
<A NAME="662"></A>
<A NAME="663"></A>        lwr();
<A NAME="664"></A>        <FONT ID="Try">try</FONT> {
<A NAME="665"></A>
<A NAME="666"></A>        <FONT ID="SingleLineComment">//Check if the group exists
<A NAME="667"></A></FONT>        result = resultStatement.executeQuery(<FONT ID="StringLiteral">"SELECT * FROM groups WHERE id="</FONT>+groupID);
<A NAME="668"></A>        <FONT ID="If">if</FONT> (!result.next())
<A NAME="669"></A>            <FONT ID="Throw">throw</FONT> <FONT ID="New">new</FONT> Exception(<FONT ID="StringLiteral">"Could not set user privileges in the group. Group does not exist."</FONT>);
<A NAME="670"></A>
<A NAME="671"></A>        <FONT ID="SingleLineComment">//Check if the user is in the group
<A NAME="672"></A></FONT>        result = resultStatement.executeQuery(<FONT ID="StringLiteral">"SELECT * FROM groupdata WHERE jabber_id='"</FONT>+escapedUser+<FONT ID="StringLiteral">"'"</FONT>);
<A NAME="673"></A>        <FONT ID="If">if</FONT> (!result.next())
<A NAME="674"></A>            <FONT ID="Throw">throw</FONT> <FONT ID="New">new</FONT> Exception(<FONT ID="StringLiteral">"Could not set user privileges in the group. User is not subscribed to the group."</FONT>);
<A NAME="675"></A>
<A NAME="676"></A>        <FONT ID="SingleLineComment">//Check whether the privileges are in allowed format
<A NAME="677"></A></FONT>        <FONT ID="If">if</FONT> (newPrivileges &lt; <FONT ID="IntegerLiteral">0</FONT> || newPrivileges &gt; <FONT ID="IntegerLiteral">7</FONT>)
<A NAME="678"></A>            <FONT ID="Throw">throw</FONT> <FONT ID="New">new</FONT> Exception(<FONT ID="StringLiteral">"Could not set user privileges in the group. Privileges are not in allowed format."</FONT>);
<A NAME="679"></A>
<A NAME="680"></A>        statement.executeUpdate(<FONT ID="StringLiteral">"UPDATE groupdata SET privileges='"</FONT>+newPrivileges+<FONT ID="StringLiteral">"' WHERE groupid="</FONT>+groupID+<FONT ID="StringLiteral">" AND "</FONT>+
<A NAME="681"></A>                                <FONT ID="StringLiteral">"jabber_id='"</FONT>+escapedUser+<FONT ID="StringLiteral">"'"</FONT>);
<A NAME="682"></A>
<A NAME="683"></A>        } <FONT ID="Finally">finally</FONT> {
<A NAME="684"></A>            uwr();
<A NAME="685"></A>        }
<A NAME="686"></A>
<A NAME="687"></A>        <FONT ID="Return">return</FONT> <FONT ID="StringLiteral">"Group privileges of user "</FONT>+user+<FONT ID="StringLiteral">" for group number "</FONT>+groupID+<FONT ID="StringLiteral">" have been set to "</FONT>+newPrivileges;
<A NAME="688"></A>    }
<A NAME="689"></A>
<A NAME="690"></A>    <FONT ID="FormalComment">/**
<A NAME="691"></A>     * Queries the DB for all groups and their descriptions
<A NAME="692"></A>     *
<A NAME="693"></A>     * @return  The string with all groups and their descriptions
<A NAME="694"></A>     * @throws  Exception   In case of DB access error
<A NAME="695"></A>     */</FONT>
<A NAME="696"></A>    <FONT ID="Public">public</FONT> String getGroups() <FONT ID="Throws">throws</FONT> Exception{
<A NAME="697"></A>        String out;
<A NAME="698"></A>
<A NAME="699"></A>        lrr();
<A NAME="700"></A>        <FONT ID="Try">try</FONT> {
<A NAME="701"></A>
<A NAME="702"></A>        result = resultStatement.executeQuery(<FONT ID="StringLiteral">"SELECT id, group_name, description, self_subscription FROM groups"</FONT>);
<A NAME="703"></A>
<A NAME="704"></A>        out = <FONT ID="StringLiteral">"List of existing groups:\n"</FONT>;
<A NAME="705"></A>        <FONT ID="While">while</FONT> (result.next()){
<A NAME="706"></A>            out += <FONT ID="StringLiteral">"Group #"</FONT> + result.getLong(<FONT ID="IntegerLiteral">1</FONT>) + <FONT ID="StringLiteral">": \""</FONT> + unescapeSQL(result.getString(<FONT ID="StringLiteral">"group_name"</FONT>)) + <FONT ID="StringLiteral">"\""</FONT> +
<A NAME="707"></A>                    <FONT ID="StringLiteral">" user self-subscription allowed: "</FONT> + result.getBoolean(<FONT ID="StringLiteral">"self_subscription"</FONT>) + <FONT ID="StringLiteral">" \n"</FONT> +
<A NAME="708"></A>                    <FONT ID="StringLiteral">"\t"</FONT> + unescapeSQL(result.getString(<FONT ID="StringLiteral">"description"</FONT>)) + <FONT ID="StringLiteral">"\n"</FONT>;
<A NAME="709"></A>        }
<A NAME="710"></A>
<A NAME="711"></A>        } <FONT ID="Finally">finally</FONT> {
<A NAME="712"></A>            urr();
<A NAME="713"></A>        }
<A NAME="714"></A>
<A NAME="715"></A>        <FONT ID="Return">return</FONT> out;
<A NAME="716"></A>    }
<A NAME="717"></A>
<A NAME="718"></A>    <FONT ID="FormalComment">/**
<A NAME="719"></A>     * Finds the first group with the given name and returns it ID number
<A NAME="720"></A>     *
<A NAME="721"></A>     * @param   groupname   The name of the group
<A NAME="722"></A>     * @throws  Exception   If no group with the given name exists
<A NAME="723"></A>     * @return              The ID number of the first grou with the given name
<A NAME="724"></A>     */</FONT>
<A NAME="725"></A>    <FONT ID="Public">public</FONT> <FONT ID="Long">long</FONT> getGroupID(String groupname) <FONT ID="Throws">throws</FONT> Exception{
<A NAME="726"></A>        String escapedName = escapeSQL(groupname);
<A NAME="727"></A>
<A NAME="728"></A>        lrr();
<A NAME="729"></A>        <FONT ID="Try">try</FONT> {
<A NAME="730"></A>
<A NAME="731"></A>        result = resultStatement.executeQuery(<FONT ID="StringLiteral">"SELECT id FROM groups WHERE group_name='"</FONT>+escapedName+<FONT ID="StringLiteral">"'"</FONT>);
<A NAME="732"></A>        <FONT ID="If">if</FONT> (!result.next()) <FONT ID="Throw">throw</FONT> <FONT ID="New">new</FONT> Exception(<FONT ID="StringLiteral">"Group of given name does not exist"</FONT>);
<A NAME="733"></A>
<A NAME="734"></A>        } <FONT ID="Finally">finally</FONT> {
<A NAME="735"></A>            urr();
<A NAME="736"></A>        }
<A NAME="737"></A>
<A NAME="738"></A>        <FONT ID="Return">return</FONT> result.getLong(<FONT ID="StringLiteral">"id"</FONT>);
<A NAME="739"></A>    }
<A NAME="740"></A>
<A NAME="741"></A>    <FONT ID="FormalComment">/**
<A NAME="742"></A>     * Determines whether the given user can modify the given group
<A NAME="743"></A>     *
<A NAME="744"></A>     * @param   user        The user whose privileges we question
<A NAME="745"></A>     * @param   groupID     ID number of the group in question
<A NAME="746"></A>     * @throws  Exception   If the user isn't a user from the group or the group doesn't exist or if the DB access fails
<A NAME="747"></A>     * @return              True if the user can modify the group, false otherwise
<A NAME="748"></A>     */</FONT>
<A NAME="749"></A>    <FONT ID="Public">public</FONT> <FONT ID="Boolean">boolean</FONT> userCanModifyGroup(String user, <FONT ID="Long">long</FONT> groupID) <FONT ID="Throws">throws</FONT> Exception{
<A NAME="750"></A>        String escapedUser = escapeSQL(user);
<A NAME="751"></A>
<A NAME="752"></A>        lrr();
<A NAME="753"></A>        <FONT ID="Try">try</FONT> {
<A NAME="754"></A>
<A NAME="755"></A>        result = resultStatement.executeQuery(<FONT ID="StringLiteral">"SELECT privileges FROM groupdata WHERE jabber_id='"</FONT>+escapedUser+<FONT ID="StringLiteral">"' AND groupid="</FONT>+groupID);
<A NAME="756"></A>        <FONT ID="If">if</FONT> (!result.next()) <FONT ID="Throw">throw</FONT> <FONT ID="New">new</FONT> Exception(<FONT ID="StringLiteral">"User "</FONT>+user+<FONT ID="StringLiteral">" doesn't belong to group number "</FONT>+groupID+<FONT ID="StringLiteral">" or no such group exists."</FONT>);
<A NAME="757"></A>        <FONT ID="If">if</FONT> ((result.getInt(<FONT ID="StringLiteral">"privileges"</FONT>) &amp; <FONT ID="IntegerLiteral">1</FONT>) == <FONT ID="IntegerLiteral">1</FONT>)
<A NAME="758"></A>            <FONT ID="Return">return</FONT> <FONT ID="True">true</FONT>;
<A NAME="759"></A>        <FONT ID="Else">else</FONT> <FONT ID="Return">return</FONT> <FONT ID="False">false</FONT>;
<A NAME="760"></A>
<A NAME="761"></A>        } <FONT ID="Finally">finally</FONT> {
<A NAME="762"></A>            urr();
<A NAME="763"></A>        }
<A NAME="764"></A>    }
<A NAME="765"></A>
<A NAME="766"></A>    <FONT ID="FormalComment">/**
<A NAME="767"></A>     * Determines whether the given user can view the given group info
<A NAME="768"></A>     *
<A NAME="769"></A>     * @param   user        The user whose privileges we question
<A NAME="770"></A>     * @param   groupID     ID number of the group in question
<A NAME="771"></A>     * @throws  Exception   If the user isn't a user from the group or the group doesn't exist or if the DB access fails
<A NAME="772"></A>     * @return              True if the user can view the group info, false otherwise
<A NAME="773"></A>     */</FONT>
<A NAME="774"></A>    <FONT ID="Public">public</FONT> <FONT ID="Boolean">boolean</FONT> userCanListGroup(String user, <FONT ID="Long">long</FONT> groupID) <FONT ID="Throws">throws</FONT> Exception{
<A NAME="775"></A>        String escapedUser = escapeSQL(user);
<A NAME="776"></A>
<A NAME="777"></A>        lrr();
<A NAME="778"></A>        <FONT ID="Try">try</FONT> {
<A NAME="779"></A>
<A NAME="780"></A>        result = resultStatement.executeQuery(<FONT ID="StringLiteral">"SELECT privileges FROM groupdata WHERE jabber_id='"</FONT>+escapedUser+<FONT ID="StringLiteral">"' AND groupid="</FONT>+groupID);
<A NAME="781"></A>        <FONT ID="If">if</FONT> (!result.next()) <FONT ID="Throw">throw</FONT> <FONT ID="New">new</FONT> Exception(<FONT ID="StringLiteral">"User "</FONT>+user+<FONT ID="StringLiteral">" doesn't belong to group number "</FONT>+groupID+<FONT ID="StringLiteral">" or no such group exists."</FONT>);
<A NAME="782"></A>        <FONT ID="If">if</FONT> ((result.getInt(<FONT ID="StringLiteral">"privileges"</FONT>) &amp; <FONT ID="IntegerLiteral">2</FONT>) == <FONT ID="IntegerLiteral">2</FONT>)
<A NAME="783"></A>            <FONT ID="Return">return</FONT> <FONT ID="True">true</FONT>;
<A NAME="784"></A>        <FONT ID="Else">else</FONT> <FONT ID="Return">return</FONT> <FONT ID="False">false</FONT>;
<A NAME="785"></A>
<A NAME="786"></A>        } <FONT ID="Finally">finally</FONT> {
<A NAME="787"></A>            urr();
<A NAME="788"></A>        }
<A NAME="789"></A>    }
<A NAME="790"></A>
<A NAME="791"></A>    <FONT ID="FormalComment">/**
<A NAME="792"></A>     * Determines whether the given user can plan events for the given group
<A NAME="793"></A>     *
<A NAME="794"></A>     * @param   user        The user whose privileges we question
<A NAME="795"></A>     * @param   groupID     ID number of the group in question
<A NAME="796"></A>     * @throws  Exception   If the user isn't a user from the group or the group doesn't exist or if the DB access fails
<A NAME="797"></A>     * @return              True if the user can plan events for the group, false otherwise
<A NAME="798"></A>     */</FONT>
<A NAME="799"></A>    <FONT ID="Public">public</FONT> <FONT ID="Boolean">boolean</FONT> userCanPlanGroup(String user, <FONT ID="Long">long</FONT> groupID) <FONT ID="Throws">throws</FONT> Exception{
<A NAME="800"></A>        String escapedUser = escapeSQL(user);
<A NAME="801"></A>
<A NAME="802"></A>        lrr();
<A NAME="803"></A>        <FONT ID="Try">try</FONT> {
<A NAME="804"></A>
<A NAME="805"></A>        result = resultStatement.executeQuery(<FONT ID="StringLiteral">"SELECT privileges FROM groupdata WHERE jabber_id='"</FONT>+escapedUser+<FONT ID="StringLiteral">"' AND groupid="</FONT>+groupID);
<A NAME="806"></A>        <FONT ID="If">if</FONT> (!result.next()) <FONT ID="Throw">throw</FONT> <FONT ID="New">new</FONT> Exception(<FONT ID="StringLiteral">"User "</FONT>+user+<FONT ID="StringLiteral">" doesn't belong to group number "</FONT>+groupID+<FONT ID="StringLiteral">" or no such group exists."</FONT>);
<A NAME="807"></A>        <FONT ID="If">if</FONT> ((result.getInt(<FONT ID="StringLiteral">"privileges"</FONT>) &amp; <FONT ID="IntegerLiteral">4</FONT>) == <FONT ID="IntegerLiteral">4</FONT>)
<A NAME="808"></A>            <FONT ID="Return">return</FONT> <FONT ID="True">true</FONT>;
<A NAME="809"></A>        <FONT ID="Else">else</FONT> <FONT ID="Return">return</FONT> <FONT ID="False">false</FONT>;
<A NAME="810"></A>
<A NAME="811"></A>        } <FONT ID="Finally">finally</FONT> {
<A NAME="812"></A>            urr();
<A NAME="813"></A>        }
<A NAME="814"></A>    }
<A NAME="815"></A>
<A NAME="816"></A>    <FONT ID="FormalComment">/**
<A NAME="817"></A>     * Determines whether ordinary users can subscribe to the group
<A NAME="818"></A>     *
<A NAME="819"></A>     * @param   groupID     ID number of the group in question
<A NAME="820"></A>     * @throws  Exception   If the group doesn't exist or in case of DB access failure
<A NAME="821"></A>     * @return              True if users can subscribe to the group, false otherwise
<A NAME="822"></A>    */</FONT>
<A NAME="823"></A>    <FONT ID="Public">public</FONT> <FONT ID="Boolean">boolean</FONT> usersCanSubscribe(<FONT ID="Long">long</FONT> groupID) <FONT ID="Throws">throws</FONT> Exception{
<A NAME="824"></A>        lrr();
<A NAME="825"></A>        <FONT ID="Try">try</FONT> {
<A NAME="826"></A>
<A NAME="827"></A>        result = resultStatement.executeQuery(<FONT ID="StringLiteral">"SELECT self_subscription FROM groups WHERE id="</FONT>+groupID);
<A NAME="828"></A>        <FONT ID="If">if</FONT> (!result.next()) <FONT ID="Throw">throw</FONT> <FONT ID="New">new</FONT> Exception(<FONT ID="StringLiteral">"Group number "</FONT>+groupID+<FONT ID="StringLiteral">" does not exist."</FONT>);
<A NAME="829"></A>        <FONT ID="If">if</FONT> (result.getBoolean(<FONT ID="StringLiteral">"self_subscription"</FONT>) == <FONT ID="True">true</FONT>)
<A NAME="830"></A>            <FONT ID="Return">return</FONT> <FONT ID="True">true</FONT>;
<A NAME="831"></A>        <FONT ID="Else">else</FONT> <FONT ID="Return">return</FONT> <FONT ID="False">false</FONT>;
<A NAME="832"></A>
<A NAME="833"></A>        } <FONT ID="Finally">finally</FONT> {
<A NAME="834"></A>            urr();
<A NAME="835"></A>        }
<A NAME="836"></A>    }
<A NAME="837"></A>
<A NAME="838"></A>    <FONT ID="FormalComment">/**
<A NAME="839"></A>     * Adds an event to the event table in the DB.
<A NAME="840"></A>     *
<A NAME="841"></A>     * The event must be in the future of the current server time. This method serves for planning both user and group events.
<A NAME="842"></A>     * Whether the event is a user or group event is determined in the PlanStruct.singleuser atribute
<A NAME="843"></A>     *
<A NAME="844"></A>     * @param   struc       The structure, containing information about the plan to be added
<A NAME="845"></A>     * @throws  Exception   In case of invalid user or group name or in case of DB access error
<A NAME="846"></A>     */</FONT>
<A NAME="847"></A>    <FONT ID="Public">public</FONT> <FONT ID="Void">void</FONT> addEvent(<A HREF="../../czestmyr/jjsched/PlanStruct.java.html">PlanStruct</A> struc) <FONT ID="Throws">throws</FONT> Exception{
<A NAME="848"></A>        <FONT ID="SingleLineComment">//Check if the timestamp is in future by subtracting current time and checking against
<A NAME="849"></A></FONT>        <FONT ID="SingleLineComment">//an arbitrary number of seconds: 10
<A NAME="850"></A></FONT>        <FONT ID="If">if</FONT> (struc.timestamp - System.currentTimeMillis() &lt; -<FONT ID="IntegerLiteral">10000</FONT>) <FONT ID="Throw">throw</FONT> <FONT ID="New">new</FONT> Exception (<FONT ID="StringLiteral">"Cannot add a planned event - event lies in past"</FONT>);
<A NAME="851"></A>
<A NAME="852"></A>        <FONT ID="SingleLineComment">//In every case, we need to escape user input
<A NAME="853"></A></FONT>        struc.username = escapeSQL(struc.username);
<A NAME="854"></A>        struc.description = escapeSQL(struc.description);
<A NAME="855"></A>
<A NAME="856"></A>        lwr();
<A NAME="857"></A>        <FONT ID="Try">try</FONT> {
<A NAME="858"></A>
<A NAME="859"></A>        <FONT ID="SingleLineComment">//The event should be planned for a single user
<A NAME="860"></A></FONT>        <FONT ID="If">if</FONT> (struc.singleuser) {
<A NAME="861"></A>            <FONT ID="SingleLineComment">//Check if the user exists
<A NAME="862"></A></FONT>            UserData user = userCache.get(struc.username);
<A NAME="863"></A>            <FONT ID="If">if</FONT> (user == <FONT ID="Null">null</FONT>) <FONT ID="Throw">throw</FONT> <FONT ID="New">new</FONT> Exception(<FONT ID="StringLiteral">"Cannot add a planned event - invalid username: "</FONT>+struc.username);
<A NAME="864"></A>
<A NAME="865"></A>            statement.executeUpdate(<FONT ID="StringLiteral">"INSERT INTO events (`time`,`user_or_group_id`,`description`,`groupevent`) "</FONT>
<A NAME="866"></A>                                  + <FONT ID="StringLiteral">"VALUES ('"</FONT>+timeHandler.getSqlFormattedTime(struc.timestamp)
<A NAME="867"></A>                                  + <FONT ID="StringLiteral">"',"</FONT>+user.user_id+<FONT ID="StringLiteral">",'"</FONT>+struc.description+<FONT ID="StringLiteral">"','0')"</FONT>);
<A NAME="868"></A>        <FONT ID="SingleLineComment">//The event is for a whole group
<A NAME="869"></A></FONT>        } <FONT ID="Else">else</FONT> {
<A NAME="870"></A>            <FONT ID="Long">long</FONT> id;
<A NAME="871"></A>
<A NAME="872"></A>            <FONT ID="If">if</FONT> (struc.groupId == <FONT ID="IntegerLiteral">0</FONT>) {
<A NAME="873"></A>                <FONT ID="SingleLineComment">//Check whether the group exists and get the group id
<A NAME="874"></A></FONT>                result = resultStatement.executeQuery(<FONT ID="StringLiteral">"SELECT id FROM groups WHERE group_name = '"</FONT>+struc.username+<FONT ID="StringLiteral">"'"</FONT>);
<A NAME="875"></A>                <FONT ID="If">if</FONT> (!result.next()) <FONT ID="Throw">throw</FONT> <FONT ID="New">new</FONT> Exception(<FONT ID="StringLiteral">"Cannot add a planned event - invalid group name: "</FONT>+struc.username);
<A NAME="876"></A>                id = result.getLong(<FONT ID="StringLiteral">"id"</FONT>);
<A NAME="877"></A>            } <FONT ID="Else">else</FONT> id = struc.groupId;
<A NAME="878"></A>
<A NAME="879"></A>                <FONT ID="SingleLineComment">//Insert the new group event
<A NAME="880"></A></FONT>                statement.executeUpdate(<FONT ID="StringLiteral">"INSERT INTO events (`time`,`user_or_group_id`,`description`,`groupevent`) "</FONT>
<A NAME="881"></A>                                      + <FONT ID="StringLiteral">"VALUES ('"</FONT>+timeHandler.getSqlFormattedTime(struc.timestamp)
<A NAME="882"></A>                                      + <FONT ID="StringLiteral">"',"</FONT>+id+<FONT ID="StringLiteral">",'"</FONT>+struc.description+<FONT ID="StringLiteral">"','1')"</FONT>);
<A NAME="883"></A>        }
<A NAME="884"></A>
<A NAME="885"></A>        } <FONT ID="Finally">finally</FONT> {
<A NAME="886"></A>            uwr();
<A NAME="887"></A>        }
<A NAME="888"></A>    }
<A NAME="889"></A>
<A NAME="890"></A>    <FONT ID="FormalComment">/**
<A NAME="891"></A>     * Unocks the result statement lock.
<A NAME="892"></A>     *
<A NAME="893"></A>     * This indicates that the statement can be reused because this thread stopped using the previous ResultSet.
<A NAME="894"></A>     */</FONT>
<A NAME="895"></A>    <FONT ID="Public">public</FONT> <FONT ID="Void">void</FONT> dropResults() {
<A NAME="896"></A>        resultLock.unlock();
<A NAME="897"></A>    }
<A NAME="898"></A>
<A NAME="899"></A>    <FONT ID="FormalComment">/**
<A NAME="900"></A>     * Returns the result set of all user events older than the given timestamp.
<A NAME="901"></A>     *
<A NAME="902"></A>     * @param   timestamp   Timestamp as given by System.currentTimeMillis()
<A NAME="903"></A>     * @return              Result set of all the desired events
<A NAME="904"></A>     * @throws  Exception   In case of DB access error
<A NAME="905"></A>     */</FONT>
<A NAME="906"></A>    <FONT ID="Public">public</FONT> ResultSet getUserEventsOlderThan(<FONT ID="Long">long</FONT> timestamp) <FONT ID="Throws">throws</FONT> Exception{
<A NAME="907"></A>        String time = timeHandler.getSqlFormattedTime(timestamp);
<A NAME="908"></A>
<A NAME="909"></A>        lrr();
<A NAME="910"></A>        <FONT ID="Try">try</FONT> {
<A NAME="911"></A>
<A NAME="912"></A>        result = resultStatement.executeQuery(<FONT ID="StringLiteral">"SELECT ev.description, us.jabber_id FROM events AS ev INNER JOIN users AS us "</FONT>+
<A NAME="913"></A>                                        <FONT ID="StringLiteral">"ON ev.user_or_group_id = us.id "</FONT>+
<A NAME="914"></A>                                        <FONT ID="StringLiteral">"WHERE groupevent = 0 AND time &lt; "</FONT>+time);
<A NAME="915"></A>
<A NAME="916"></A>        } <FONT ID="Finally">finally</FONT> {
<A NAME="917"></A>            ur(); <FONT ID="SingleLineComment">//This is not a mistake. resultLock should be locked outside when the result set is not used anymore
<A NAME="918"></A></FONT>        }
<A NAME="919"></A>
<A NAME="920"></A>        <FONT ID="Return">return</FONT> result;
<A NAME="921"></A>    }
<A NAME="922"></A>
<A NAME="923"></A>    <FONT ID="FormalComment">/**
<A NAME="924"></A>     * Returns a string with a list of all events of a given user.
<A NAME="925"></A>     * 
<A NAME="926"></A>     * @param   userId  Jabber ID of the user whose events should be listed
<A NAME="927"></A>     * @return      List of all the user's events
<A NAME="928"></A>     */</FONT>
<A NAME="929"></A>    <FONT ID="Public">public</FONT> String listUserEvents(String userId) <FONT ID="Throws">throws</FONT> Exception{
<A NAME="930"></A>        lrr();
<A NAME="931"></A>        <FONT ID="Try">try</FONT> {
<A NAME="932"></A>            String ret = <FONT ID="StringLiteral">""</FONT>;
<A NAME="933"></A>            result = resultStatement.executeQuery(<FONT ID="StringLiteral">"SELECT * FROM events AS ev INNER JOIN users AS us "</FONT>+
<A NAME="934"></A>                                <FONT ID="StringLiteral">"ON ev.user_or_group_id = us.id "</FONT>+
<A NAME="935"></A>                                <FONT ID="StringLiteral">"WHERE groupevent = 0 AND jabber_id = '"</FONT>+userId+<FONT ID="StringLiteral">"' ORDER BY time ASC"</FONT>);
<A NAME="936"></A>
<A NAME="937"></A>            <FONT ID="While">while</FONT> (result.next()) {
<A NAME="938"></A>                ret += timeHandler.getFormattedTime(result.getTimestamp(<FONT ID="StringLiteral">"time"</FONT>).getTime());
<A NAME="939"></A>                ret += <FONT ID="StringLiteral">" / "</FONT>;
<A NAME="940"></A>                ret += result.getString(<FONT ID="StringLiteral">"description"</FONT>);
<A NAME="941"></A>                ret += <FONT ID="StringLiteral">"\n"</FONT>;
<A NAME="942"></A>            }
<A NAME="943"></A>            <FONT ID="Return">return</FONT> ret;
<A NAME="944"></A>        } <FONT ID="Catch">catch</FONT> (Exception e) {
<A NAME="945"></A>            <FONT ID="Return">return</FONT> e.getMessage();
<A NAME="946"></A>        } <FONT ID="Finally">finally</FONT> {
<A NAME="947"></A>            urr();
<A NAME="948"></A>        }
<A NAME="949"></A>    }
<A NAME="950"></A>
<A NAME="951"></A>    <FONT ID="FormalComment">/**
<A NAME="952"></A>     * Returns a string with a list of all events of a given group.
<A NAME="953"></A>     * 
<A NAME="954"></A>     * @param   groupId Group number of the group whose events should be listed
<A NAME="955"></A>     * @return      List of all the group's events
<A NAME="956"></A>     */</FONT>
<A NAME="957"></A>    <FONT ID="Public">public</FONT> String listGroupEvents(<FONT ID="Long">long</FONT> groupId) <FONT ID="Throws">throws</FONT> Exception{
<A NAME="958"></A>        lrr();
<A NAME="959"></A>        <FONT ID="Try">try</FONT> {
<A NAME="960"></A>            String ret = <FONT ID="StringLiteral">""</FONT>;
<A NAME="961"></A>            result = resultStatement.executeQuery(<FONT ID="StringLiteral">"SELECT * FROM events WHERE groupevent = 1 AND user_or_group_id = "</FONT>+groupId+<FONT ID="StringLiteral">" ORDER BY time ASC"</FONT>);
<A NAME="962"></A>
<A NAME="963"></A>            <FONT ID="While">while</FONT> (result.next()) {
<A NAME="964"></A>                ret += timeHandler.getFormattedTime(result.getTimestamp(<FONT ID="StringLiteral">"time"</FONT>).getTime());
<A NAME="965"></A>                ret += <FONT ID="StringLiteral">" / "</FONT>;
<A NAME="966"></A>                ret += result.getString(<FONT ID="StringLiteral">"description"</FONT>);
<A NAME="967"></A>                ret += <FONT ID="StringLiteral">"\n"</FONT>;
<A NAME="968"></A>            }
<A NAME="969"></A>            <FONT ID="Return">return</FONT> ret;
<A NAME="970"></A>        } <FONT ID="Catch">catch</FONT> (Exception e) {
<A NAME="971"></A>            <FONT ID="Return">return</FONT> e.getMessage();
<A NAME="972"></A>        } <FONT ID="Finally">finally</FONT> {
<A NAME="973"></A>            urr();
<A NAME="974"></A>        }
<A NAME="975"></A>    }
<A NAME="976"></A>
<A NAME="977"></A>    <FONT ID="FormalComment">/**
<A NAME="978"></A>     * Deletes user events older than timestamp from the database
<A NAME="979"></A>     *
<A NAME="980"></A>     * @param   timestamp   Timestamp as given by System.currentTimeMillis()
<A NAME="981"></A>     * @throws  Exception   In case of DB access error
<A NAME="982"></A>     */</FONT>
<A NAME="983"></A>    <FONT ID="Public">public</FONT> <FONT ID="Void">void</FONT> deleteUserEventsOlderThan(<FONT ID="Long">long</FONT> timestamp) <FONT ID="Throws">throws</FONT> Exception{
<A NAME="984"></A>        String time = timeHandler.getSqlFormattedTime(timestamp);
<A NAME="985"></A>
<A NAME="986"></A>        lw();
<A NAME="987"></A>        <FONT ID="Try">try</FONT> {
<A NAME="988"></A>
<A NAME="989"></A>        statement.executeUpdate(<FONT ID="StringLiteral">"DELETE FROM events WHERE groupevent = 0 AND time &lt; "</FONT>+time);
<A NAME="990"></A>
<A NAME="991"></A>        } <FONT ID="Finally">finally</FONT> {
<A NAME="992"></A>            uw();
<A NAME="993"></A>        }
<A NAME="994"></A>    }
<A NAME="995"></A>
<A NAME="996"></A>    <FONT ID="FormalComment">/**
<A NAME="997"></A>     * Returns the result set of all group events older than the given timestamp.
<A NAME="998"></A>     *
<A NAME="999"></A>     * @param   timestamp   Timestamp as given by System.currentTimeMillis()
<A NAME="1000"></A>     * @return              Result set of all the desired events
<A NAME="1001"></A>     * @throws  Exception   In case of DB access error
<A NAME="1002"></A>     */</FONT>
<A NAME="1003"></A>    <FONT ID="Public">public</FONT> ResultSet getGroupEventsOlderThan(<FONT ID="Long">long</FONT> timestamp) <FONT ID="Throws">throws</FONT> Exception{
<A NAME="1004"></A>        String time = timeHandler.getSqlFormattedTime(timestamp);
<A NAME="1005"></A>
<A NAME="1006"></A>        lrr();
<A NAME="1007"></A>        <FONT ID="Try">try</FONT> {
<A NAME="1008"></A>
<A NAME="1009"></A>        result = resultStatement.executeQuery(<FONT ID="StringLiteral">"SELECT ev.description, us.jabber_id FROM events AS ev INNER JOIN groupdata as gd "</FONT>+
<A NAME="1010"></A>                                        <FONT ID="StringLiteral">"ON ev.user_or_group_id = gd.groupid INNER JOIN users AS us "</FONT>+
<A NAME="1011"></A>                                        <FONT ID="StringLiteral">"ON gd.jabber_id = us.jabber_id "</FONT>+
<A NAME="1012"></A>                                        <FONT ID="StringLiteral">"WHERE groupevent = 1 AND time &lt; "</FONT>+time);
<A NAME="1013"></A>        } <FONT ID="Finally">finally</FONT> {
<A NAME="1014"></A>            ur(); <FONT ID="SingleLineComment">//This is not a mistake. resultLock should be unlocked outside when the result set is not used anymore
<A NAME="1015"></A></FONT>        }
<A NAME="1016"></A>
<A NAME="1017"></A>        <FONT ID="Return">return</FONT> result;
<A NAME="1018"></A>    }
<A NAME="1019"></A>
<A NAME="1020"></A>    <FONT ID="FormalComment">/**
<A NAME="1021"></A>     * Deletes group events older than timestamp from the database
<A NAME="1022"></A>     *
<A NAME="1023"></A>     * @param   timestamp   Timestamp as given by System.currentTimeMillis()
<A NAME="1024"></A>     * @throws  Exception   In case of DB access error
<A NAME="1025"></A>     */</FONT>
<A NAME="1026"></A>    <FONT ID="Public">public</FONT> <FONT ID="Void">void</FONT> deleteGroupEventsOlderThan(<FONT ID="Long">long</FONT> timestamp) <FONT ID="Throws">throws</FONT> Exception{
<A NAME="1027"></A>        String time = timeHandler.getSqlFormattedTime(timestamp);
<A NAME="1028"></A>
<A NAME="1029"></A>        lw();
<A NAME="1030"></A>        <FONT ID="Try">try</FONT> {
<A NAME="1031"></A>            statement.executeUpdate(<FONT ID="StringLiteral">"DELETE FROM events WHERE groupevent = 1 AND time &lt; "</FONT>+time);
<A NAME="1032"></A>        } <FONT ID="Finally">finally</FONT> {
<A NAME="1033"></A>            uw();
<A NAME="1034"></A>        }
<A NAME="1035"></A>    }
<A NAME="1036"></A>
<A NAME="1037"></A>    <FONT ID="FormalComment">/**
<A NAME="1038"></A>     * Check, whether the DB has the right structure.
<A NAME="1039"></A>     * @throws Exception In case of DB access failure
<A NAME="1040"></A>     */</FONT>
<A NAME="1041"></A>    <FONT ID="Private">private</FONT> <FONT ID="Void">void</FONT> checkDB() <FONT ID="Throws">throws</FONT> Exception{
<A NAME="1042"></A>        lrr();
<A NAME="1043"></A>        <FONT ID="Try">try</FONT> {
<A NAME="1044"></A>
<A NAME="1045"></A>        DatabaseMetaData dbmd = conn.getMetaData();
<A NAME="1046"></A>        String confSchema = conf.getString(<FONT ID="StringLiteral">"MySQLScheme"</FONT>);
<A NAME="1047"></A>
<A NAME="1048"></A>        <FONT ID="SingleLineComment">//Find out, whether the schema contains all the needed Tables
<A NAME="1049"></A></FONT>        String[] tables = {<FONT ID="StringLiteral">"users"</FONT>, <FONT ID="StringLiteral">"events"</FONT>, <FONT ID="StringLiteral">"groups"</FONT>, <FONT ID="StringLiteral">"groupdata"</FONT>, <FONT ID="StringLiteral">"admins"</FONT>};
<A NAME="1050"></A>        <FONT ID="For">for</FONT> (String tableName: tables) {
<A NAME="1051"></A>            result = dbmd.getTables(<FONT ID="Null">null</FONT>, confSchema, tableName, <FONT ID="Null">null</FONT>);
<A NAME="1052"></A>            <FONT ID="If">if</FONT> (!result.next())
<A NAME="1053"></A>                <FONT ID="Throw">throw</FONT> <FONT ID="New">new</FONT> Exception(<FONT ID="StringLiteral">"DB inconsistency error: Scheme "</FONT>+confSchema+<FONT ID="StringLiteral">" does not contain table \""</FONT>+tableName+<FONT ID="StringLiteral">"\""</FONT>);
<A NAME="1054"></A>        }
<A NAME="1055"></A>
<A NAME="1056"></A>        String[] columns = <FONT ID="Null">null</FONT>;
<A NAME="1057"></A>        <FONT ID="Int">int</FONT>[] columnTypes = <FONT ID="Null">null</FONT>;
<A NAME="1058"></A>        String tableName = <FONT ID="Null">null</FONT>;
<A NAME="1059"></A>
<A NAME="1060"></A>        <FONT ID="SingleLineComment">//Check for the correct form of table 'users'
<A NAME="1061"></A></FONT>        tableName = <FONT ID="StringLiteral">"users"</FONT>;
<A NAME="1062"></A>        columns = <FONT ID="New">new</FONT> String[]  {<FONT ID="StringLiteral">"jabber_id"</FONT>,   <FONT ID="StringLiteral">"id"</FONT>,          <FONT ID="StringLiteral">"gmt_offset"</FONT>};
<A NAME="1063"></A>        columnTypes = <FONT ID="New">new</FONT> <FONT ID="Int">int</FONT>[] {Types.VARCHAR, Types.INTEGER, Types.INTEGER};
<A NAME="1064"></A>        <FONT ID="For">for</FONT> (<FONT ID="Int">int</FONT> i = <FONT ID="IntegerLiteral">0</FONT>; i &lt; columns.length; ++i){
<A NAME="1065"></A>            result = dbmd.getColumns(<FONT ID="Null">null</FONT>, confSchema, tableName, columns[i]);
<A NAME="1066"></A>            <FONT ID="If">if</FONT> (!result.next())
<A NAME="1067"></A>                <FONT ID="Throw">throw</FONT> <FONT ID="New">new</FONT> Exception(<FONT ID="StringLiteral">"DB inconsistency error: Table \""</FONT>+tableName+
<A NAME="1068"></A>                                    <FONT ID="StringLiteral">"\" does not have a column named \""</FONT>+columns[i]+<FONT ID="StringLiteral">"\""</FONT>);
<A NAME="1069"></A>            <FONT ID="If">if</FONT> (result.getInt(<FONT ID="StringLiteral">"DATA_TYPE"</FONT>) != columnTypes[i])
<A NAME="1070"></A>                <FONT ID="Throw">throw</FONT> <FONT ID="New">new</FONT> Exception(<FONT ID="StringLiteral">"DB inconsistency error: Column \""</FONT>+columns[i]+
<A NAME="1071"></A>                                    <FONT ID="StringLiteral">"\" in table \""</FONT>+tableName+<FONT ID="StringLiteral">"\" does not match spec."</FONT>);
<A NAME="1072"></A>        }
<A NAME="1073"></A>        result = dbmd.getColumns(<FONT ID="Null">null</FONT>, confSchema, tableName, <FONT ID="Null">null</FONT>);
<A NAME="1074"></A>        <FONT ID="While">while</FONT> (result.next())
<A NAME="1075"></A>            <FONT ID="If">if</FONT> (!Arrays.asList(columns).contains(result.getString(<FONT ID="StringLiteral">"COLUMN_NAME"</FONT>)))
<A NAME="1076"></A>                <FONT ID="Throw">throw</FONT> <FONT ID="New">new</FONT> Exception(<FONT ID="StringLiteral">"DB inconsistency error: Table \""</FONT>+tableName+
<A NAME="1077"></A>                                    <FONT ID="StringLiteral">"\" has a column (\""</FONT>+result.getString(<FONT ID="StringLiteral">"COLUMN_NAME"</FONT>)+<FONT ID="StringLiteral">"\") that is not in spec."</FONT>);
<A NAME="1078"></A>
<A NAME="1079"></A>        <FONT ID="SingleLineComment">//Check for the correct form of table 'events'
<A NAME="1080"></A></FONT>        tableName = <FONT ID="StringLiteral">"events"</FONT>;
<A NAME="1081"></A>        columns = <FONT ID="New">new</FONT> String[]  {<FONT ID="StringLiteral">"id"</FONT>,          <FONT ID="StringLiteral">"groupevent"</FONT>,  <FONT ID="StringLiteral">"user_or_group_id"</FONT>, <FONT ID="StringLiteral">"time"</FONT>,          <FONT ID="StringLiteral">"description"</FONT> };
<A NAME="1082"></A>        columnTypes = <FONT ID="New">new</FONT> <FONT ID="Int">int</FONT>[] {Types.INTEGER, Types.TINYINT, Types.INTEGER,      Types.TIMESTAMP, Types.VARCHAR   };
<A NAME="1083"></A>        <FONT ID="For">for</FONT> (<FONT ID="Int">int</FONT> i = <FONT ID="IntegerLiteral">0</FONT>; i &lt; columns.length; ++i){
<A NAME="1084"></A>            result = dbmd.getColumns(<FONT ID="Null">null</FONT>, confSchema, tableName, columns[i]);
<A NAME="1085"></A>            <FONT ID="If">if</FONT> (!result.next())
<A NAME="1086"></A>                <FONT ID="Throw">throw</FONT> <FONT ID="New">new</FONT> Exception(<FONT ID="StringLiteral">"DB inconsistency error: Table \""</FONT>+tableName+
<A NAME="1087"></A>                        <FONT ID="StringLiteral">"\" does not have a column named \""</FONT>+columns[i]+<FONT ID="StringLiteral">"\""</FONT>);
<A NAME="1088"></A>            <FONT ID="If">if</FONT> (result.getInt(<FONT ID="StringLiteral">"DATA_TYPE"</FONT>) != columnTypes[i])
<A NAME="1089"></A>                <FONT ID="Throw">throw</FONT> <FONT ID="New">new</FONT> Exception(<FONT ID="StringLiteral">"DB inconsistency error: Column \""</FONT>+columns[i]+
<A NAME="1090"></A>                        <FONT ID="StringLiteral">"\" in table \""</FONT>+tableName+<FONT ID="StringLiteral">"\" does not match spec."</FONT>);
<A NAME="1091"></A>        }
<A NAME="1092"></A>        result = dbmd.getColumns(<FONT ID="Null">null</FONT>, confSchema, tableName, <FONT ID="Null">null</FONT>);
<A NAME="1093"></A>        <FONT ID="While">while</FONT> (result.next())
<A NAME="1094"></A>            <FONT ID="If">if</FONT> (!Arrays.asList(columns).contains(result.getString(<FONT ID="StringLiteral">"COLUMN_NAME"</FONT>)))
<A NAME="1095"></A>                <FONT ID="Throw">throw</FONT> <FONT ID="New">new</FONT> Exception(<FONT ID="StringLiteral">"DB inconsistency error: Table \""</FONT>+tableName+
<A NAME="1096"></A>                        <FONT ID="StringLiteral">"\" has a column (\""</FONT>+result.getString(<FONT ID="StringLiteral">"COLUMN_NAME"</FONT>)+<FONT ID="StringLiteral">"\") that is not in spec."</FONT>);
<A NAME="1097"></A>
<A NAME="1098"></A>        <FONT ID="SingleLineComment">//Check for the correct form of table 'groups'
<A NAME="1099"></A></FONT>        tableName = <FONT ID="StringLiteral">"groups"</FONT>;
<A NAME="1100"></A>        columns = <FONT ID="New">new</FONT> String[]  {<FONT ID="StringLiteral">"id"</FONT>,          <FONT ID="StringLiteral">"group_name"</FONT>,   <FONT ID="StringLiteral">"description"</FONT>, <FONT ID="StringLiteral">"self_subscription"</FONT> };
<A NAME="1101"></A>        columnTypes = <FONT ID="New">new</FONT> <FONT ID="Int">int</FONT>[] {Types.INTEGER, Types.VARCHAR,  Types.VARCHAR, Types.TINYINT   };
<A NAME="1102"></A>        <FONT ID="For">for</FONT> (<FONT ID="Int">int</FONT> i = <FONT ID="IntegerLiteral">0</FONT>; i &lt; columns.length; ++i){
<A NAME="1103"></A>            result = dbmd.getColumns(<FONT ID="Null">null</FONT>, confSchema, tableName, columns[i]);
<A NAME="1104"></A>            <FONT ID="If">if</FONT> (!result.next())
<A NAME="1105"></A>                <FONT ID="Throw">throw</FONT> <FONT ID="New">new</FONT> Exception(<FONT ID="StringLiteral">"DB inconsistency error: Table \""</FONT>+tableName+
<A NAME="1106"></A>                        <FONT ID="StringLiteral">"\" does not have a column named \""</FONT>+columns[i]+<FONT ID="StringLiteral">"\""</FONT>);
<A NAME="1107"></A>            <FONT ID="If">if</FONT> (result.getInt(<FONT ID="StringLiteral">"DATA_TYPE"</FONT>) != columnTypes[i])
<A NAME="1108"></A>                <FONT ID="Throw">throw</FONT> <FONT ID="New">new</FONT> Exception(<FONT ID="StringLiteral">"DB inconsistency error: Column \""</FONT>+columns[i]+
<A NAME="1109"></A>                        <FONT ID="StringLiteral">"\" in table \""</FONT>+tableName+<FONT ID="StringLiteral">"\" does not match spec."</FONT>);
<A NAME="1110"></A>        }
<A NAME="1111"></A>        result = dbmd.getColumns(<FONT ID="Null">null</FONT>, confSchema, tableName, <FONT ID="Null">null</FONT>);
<A NAME="1112"></A>        <FONT ID="While">while</FONT> (result.next())
<A NAME="1113"></A>            <FONT ID="If">if</FONT> (!Arrays.asList(columns).contains(result.getString(<FONT ID="StringLiteral">"COLUMN_NAME"</FONT>)))
<A NAME="1114"></A>                <FONT ID="Throw">throw</FONT> <FONT ID="New">new</FONT> Exception(<FONT ID="StringLiteral">"DB inconsistency error: Table \""</FONT>+tableName+
<A NAME="1115"></A>                        <FONT ID="StringLiteral">"\" has a column (\""</FONT>+result.getString(<FONT ID="StringLiteral">"COLUMN_NAME"</FONT>)+<FONT ID="StringLiteral">"\") that is not in spec."</FONT>);
<A NAME="1116"></A>
<A NAME="1117"></A>        <FONT ID="SingleLineComment">//Check for the correct form of table 'groupdata'
<A NAME="1118"></A></FONT>        tableName = <FONT ID="StringLiteral">"groupdata"</FONT>;
<A NAME="1119"></A>        columns = <FONT ID="New">new</FONT> String[]  {<FONT ID="StringLiteral">"recordid"</FONT>,  <FONT ID="StringLiteral">"groupid"</FONT>,   <FONT ID="StringLiteral">"jabber_id"</FONT>, <FONT ID="StringLiteral">"privileges"</FONT> };
<A NAME="1120"></A>        columnTypes = <FONT ID="New">new</FONT> <FONT ID="Int">int</FONT>[] {Types.INTEGER, Types.INTEGER, Types.VARCHAR, Types.TINYINT };
<A NAME="1121"></A>        <FONT ID="For">for</FONT> (<FONT ID="Int">int</FONT> i = <FONT ID="IntegerLiteral">0</FONT>; i &lt; columns.length; ++i){
<A NAME="1122"></A>            result = dbmd.getColumns(<FONT ID="Null">null</FONT>, confSchema, tableName, columns[i]);
<A NAME="1123"></A>            <FONT ID="If">if</FONT> (!result.next())
<A NAME="1124"></A>                <FONT ID="Throw">throw</FONT> <FONT ID="New">new</FONT> Exception(<FONT ID="StringLiteral">"DB inconsistency error: Table \""</FONT>+tableName+
<A NAME="1125"></A>                        <FONT ID="StringLiteral">"\" does not have a column named \""</FONT>+columns[i]+<FONT ID="StringLiteral">"\""</FONT>);
<A NAME="1126"></A>            <FONT ID="If">if</FONT> (result.getInt(<FONT ID="StringLiteral">"DATA_TYPE"</FONT>) != columnTypes[i])
<A NAME="1127"></A>                <FONT ID="Throw">throw</FONT> <FONT ID="New">new</FONT> Exception(<FONT ID="StringLiteral">"DB inconsistency error: Column \""</FONT>+columns[i]+
<A NAME="1128"></A>                        <FONT ID="StringLiteral">"\" in table \""</FONT>+tableName+<FONT ID="StringLiteral">"\" does not match spec."</FONT>);
<A NAME="1129"></A>        }
<A NAME="1130"></A>        result = dbmd.getColumns(<FONT ID="Null">null</FONT>, confSchema, tableName, <FONT ID="Null">null</FONT>);
<A NAME="1131"></A>        <FONT ID="While">while</FONT> (result.next())
<A NAME="1132"></A>            <FONT ID="If">if</FONT> (!Arrays.asList(columns).contains(result.getString(<FONT ID="StringLiteral">"COLUMN_NAME"</FONT>)))
<A NAME="1133"></A>                <FONT ID="Throw">throw</FONT> <FONT ID="New">new</FONT> Exception(<FONT ID="StringLiteral">"DB inconsistency error: Table \""</FONT>+tableName+
<A NAME="1134"></A>                        <FONT ID="StringLiteral">"\" has a column (\""</FONT>+result.getString(<FONT ID="StringLiteral">"COLUMN_NAME"</FONT>)+<FONT ID="StringLiteral">"\") that is not in spec."</FONT>);
<A NAME="1135"></A>
<A NAME="1136"></A>        <FONT ID="SingleLineComment">//Check for the correct form of table 'admins'
<A NAME="1137"></A></FONT>        tableName = <FONT ID="StringLiteral">"admins"</FONT>;
<A NAME="1138"></A>        columns = <FONT ID="New">new</FONT> String[]  {<FONT ID="StringLiteral">"jabber_id"</FONT>,   <FONT ID="StringLiteral">"privileges"</FONT> };
<A NAME="1139"></A>        columnTypes = <FONT ID="New">new</FONT> <FONT ID="Int">int</FONT>[] {Types.VARCHAR, Types.TINYINT};
<A NAME="1140"></A>        <FONT ID="For">for</FONT> (<FONT ID="Int">int</FONT> i = <FONT ID="IntegerLiteral">0</FONT>; i &lt; columns.length; ++i){
<A NAME="1141"></A>            result = dbmd.getColumns(<FONT ID="Null">null</FONT>, confSchema, tableName, columns[i]);
<A NAME="1142"></A>            <FONT ID="If">if</FONT> (!result.next())
<A NAME="1143"></A>                <FONT ID="Throw">throw</FONT> <FONT ID="New">new</FONT> Exception(<FONT ID="StringLiteral">"DB inconsistency error: Table \""</FONT>+tableName+
<A NAME="1144"></A>                        <FONT ID="StringLiteral">"\" does not have a column named \""</FONT>+columns[i]+<FONT ID="StringLiteral">"\""</FONT>);
<A NAME="1145"></A>            <FONT ID="If">if</FONT> (result.getInt(<FONT ID="StringLiteral">"DATA_TYPE"</FONT>) != columnTypes[i])
<A NAME="1146"></A>                <FONT ID="Throw">throw</FONT> <FONT ID="New">new</FONT> Exception(<FONT ID="StringLiteral">"DB inconsistency error: Column \""</FONT>+columns[i]+
<A NAME="1147"></A>                        <FONT ID="StringLiteral">"\" in table \""</FONT>+tableName+<FONT ID="StringLiteral">"\" does not match spec."</FONT>);
<A NAME="1148"></A>        }
<A NAME="1149"></A>        result = dbmd.getColumns(<FONT ID="Null">null</FONT>, confSchema, tableName, <FONT ID="Null">null</FONT>);
<A NAME="1150"></A>        <FONT ID="While">while</FONT> (result.next())
<A NAME="1151"></A>            <FONT ID="If">if</FONT> (!Arrays.asList(columns).contains(result.getString(<FONT ID="StringLiteral">"COLUMN_NAME"</FONT>)))
<A NAME="1152"></A>                <FONT ID="Throw">throw</FONT> <FONT ID="New">new</FONT> Exception(<FONT ID="StringLiteral">"DB inconsistency error: Table \""</FONT>+tableName+
<A NAME="1153"></A>                        <FONT ID="StringLiteral">"\" has a column (\""</FONT>+result.getString(<FONT ID="StringLiteral">"COLUMN_NAME"</FONT>)+<FONT ID="StringLiteral">"\") that is not in spec."</FONT>);
<A NAME="1154"></A>
<A NAME="1155"></A>        } <FONT ID="Finally">finally</FONT> {
<A NAME="1156"></A>            urr();
<A NAME="1157"></A>        }
<A NAME="1158"></A>    }
<A NAME="1159"></A>
<A NAME="1160"></A>    <FONT ID="FormalComment">/**
<A NAME="1161"></A>     *  Creates the needed tables in the database and schema that were specified in the config file.
<A NAME="1162"></A>     *  This function also erases the old tables, if they are in the way.
<A NAME="1163"></A>     *
<A NAME="1164"></A>     * @throws  Exception   In case of DB access error
<A NAME="1165"></A>     */</FONT>
<A NAME="1166"></A>    <FONT ID="Public">public</FONT> <FONT ID="Void">void</FONT> createTables() <FONT ID="Throws">throws</FONT> Exception{
<A NAME="1167"></A>        lw();
<A NAME="1168"></A>        <FONT ID="Try">try</FONT> {
<A NAME="1169"></A>
<A NAME="1170"></A>        DatabaseMetaData dbmd = conn.getMetaData();
<A NAME="1171"></A>        String confSchema = conf.getString(<FONT ID="StringLiteral">"MySQLScheme"</FONT>);
<A NAME="1172"></A>
<A NAME="1173"></A>        <FONT ID="SingleLineComment">//Erase the old tables, if they exist
<A NAME="1174"></A></FONT>        String[] tables = {<FONT ID="StringLiteral">"users"</FONT>, <FONT ID="StringLiteral">"events"</FONT>, <FONT ID="StringLiteral">"groups"</FONT>, <FONT ID="StringLiteral">"groupdata"</FONT>, <FONT ID="StringLiteral">"admins"</FONT>};
<A NAME="1175"></A>        <FONT ID="For">for</FONT> (String tableName: tables) {
<A NAME="1176"></A>            statement.executeUpdate(<FONT ID="StringLiteral">"DROP TABLE IF EXISTS "</FONT>+tableName);
<A NAME="1177"></A>        }
<A NAME="1178"></A>
<A NAME="1179"></A>        <FONT ID="SingleLineComment">//Create the new 'users' table
<A NAME="1180"></A></FONT>        statement.executeUpdate(<FONT ID="StringLiteral">"CREATE TABLE users ("</FONT>+
<A NAME="1181"></A>                                    <FONT ID="StringLiteral">"jabber_id VARCHAR(128) CHARSET utf8 NOT NULL UNIQUE KEY,"</FONT>+
<A NAME="1182"></A>                                    <FONT ID="StringLiteral">"id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,"</FONT>+
<A NAME="1183"></A>                                    <FONT ID="StringLiteral">"gmt_offset INTEGER NOT NULL DEFAULT 0)"</FONT>);
<A NAME="1184"></A>
<A NAME="1185"></A>        <FONT ID="SingleLineComment">//Create the new 'events' table
<A NAME="1186"></A></FONT>        statement.executeUpdate(<FONT ID="StringLiteral">"CREATE TABLE events ("</FONT>+
<A NAME="1187"></A>                                    <FONT ID="StringLiteral">"id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,"</FONT>+
<A NAME="1188"></A>                                    <FONT ID="StringLiteral">"groupevent TINYINT UNSIGNED NOT NULL,"</FONT>+
<A NAME="1189"></A>                                    <FONT ID="StringLiteral">"user_or_group_id INTEGER UNSIGNED NOT NULL,"</FONT>+
<A NAME="1190"></A>                                    <FONT ID="StringLiteral">"time TIMESTAMP NOT NULL,"</FONT>+
<A NAME="1191"></A>                                    <FONT ID="StringLiteral">"description VARCHAR(128) CHARSET utf8 NOT NULL DEFAULT '')"</FONT>);
<A NAME="1192"></A>
<A NAME="1193"></A>        <FONT ID="SingleLineComment">//Create the new 'groups' table
<A NAME="1194"></A></FONT>        statement.executeUpdate(<FONT ID="StringLiteral">"CREATE TABLE groups ("</FONT>+
<A NAME="1195"></A>                                    <FONT ID="StringLiteral">"id INTEGER UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,"</FONT>+
<A NAME="1196"></A>                                    <FONT ID="StringLiteral">"group_name VARCHAR(128) charset utf8 NOT NULL DEFAULT '',"</FONT>+
<A NAME="1197"></A>                                    <FONT ID="StringLiteral">"description VARCHAR(128) charset utf8 NOT NULL DEFAULT '',"</FONT>+
<A NAME="1198"></A>                                    <FONT ID="StringLiteral">"self_subscription TINYINT NOT NULL DEFAULT 1)"</FONT>);
<A NAME="1199"></A>
<A NAME="1200"></A>        <FONT ID="SingleLineComment">//Create the new 'groupdata' table
<A NAME="1201"></A></FONT>        statement.executeUpdate(<FONT ID="StringLiteral">"CREATE TABLE groupdata ("</FONT>+
<A NAME="1202"></A>                                    <FONT ID="StringLiteral">"recordid INTEGER UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,"</FONT>+
<A NAME="1203"></A>                                    <FONT ID="StringLiteral">"groupid INTEGER UNSIGNED NOT NULL,"</FONT>+
<A NAME="1204"></A>                                    <FONT ID="StringLiteral">"jabber_id VARCHAR(128) CHARSET utf8 NOT NULL,"</FONT>+
<A NAME="1205"></A>                                    <FONT ID="StringLiteral">"privileges TINYINT UNSIGNED NOT NULL DEFAULT 0)"</FONT>);
<A NAME="1206"></A>
<A NAME="1207"></A>        <FONT ID="SingleLineComment">//Create the new 'admins' table
<A NAME="1208"></A></FONT>        statement.executeUpdate(<FONT ID="StringLiteral">"CREATE TABLE admins ("</FONT>+
<A NAME="1209"></A>                                    <FONT ID="StringLiteral">"jabber_id VARCHAR(128) CHARSET utf8 NOT NULL PRIMARY KEY,"</FONT>+
<A NAME="1210"></A>                                    <FONT ID="StringLiteral">"privileges TINYINT UNSIGNED NOT NULL DEFAULT 0)"</FONT>);
<A NAME="1211"></A>
<A NAME="1212"></A>        <FONT ID="SingleLineComment">//Register the console admin
<A NAME="1213"></A></FONT>        registerUser(<FONT ID="StringLiteral">"console"</FONT>);
<A NAME="1214"></A>        setAdminPrivileges(<FONT ID="StringLiteral">"console"</FONT>, <FONT ID="IntegerLiteral">15</FONT>);
<A NAME="1215"></A>
<A NAME="1216"></A>        <FONT ID="SingleLineComment">//Register the initial admin and set his privileges
<A NAME="1217"></A></FONT>        String initAdmin = conf.getString(<FONT ID="StringLiteral">"InitialAdmin"</FONT>);
<A NAME="1218"></A>        initAdmin = StringParser.escapeJID(initAdmin);
<A NAME="1219"></A>        <FONT ID="If">if</FONT> (initAdmin == <FONT ID="Null">null</FONT>) initAdmin = <FONT ID="StringLiteral">"user@host.com"</FONT>;
<A NAME="1220"></A>        registerUser(initAdmin);
<A NAME="1221"></A>        setAdminPrivileges(initAdmin, <FONT ID="IntegerLiteral">15</FONT>);
<A NAME="1222"></A>
<A NAME="1223"></A>        } <FONT ID="Finally">finally</FONT> {
<A NAME="1224"></A>            uw();
<A NAME="1225"></A>        }
<A NAME="1226"></A>    }
<A NAME="1227"></A>
<A NAME="1228"></A>    <FONT ID="FormalComment">/**
<A NAME="1229"></A>     * Load users and admins from the DB into cache.
<A NAME="1230"></A>     *
<A NAME="1231"></A>     * @throws Exception In case of DB access error
<A NAME="1232"></A>     */</FONT>
<A NAME="1233"></A>    <FONT ID="Private">private</FONT> <FONT ID="Void">void</FONT> mirrorCaches() <FONT ID="Throws">throws</FONT> Exception{
<A NAME="1234"></A>        lwr();
<A NAME="1235"></A>        <FONT ID="Try">try</FONT> {
<A NAME="1236"></A>
<A NAME="1237"></A>        result = resultStatement.executeQuery(<FONT ID="StringLiteral">"SELECT id, jabber_id, gmt_offset FROM users"</FONT>);
<A NAME="1238"></A>
<A NAME="1239"></A>        <FONT ID="While">while</FONT> (result.next()){
<A NAME="1240"></A>            userCache.put(result.getString(<FONT ID="StringLiteral">"jabber_id"</FONT>),
<A NAME="1241"></A>                          <FONT ID="New">new</FONT> UserData(result.getInt(<FONT ID="StringLiteral">"id"</FONT>), result.getInt(<FONT ID="StringLiteral">"gmt_offset"</FONT>)));
<A NAME="1242"></A>        }
<A NAME="1243"></A>
<A NAME="1244"></A>        result = resultStatement.executeQuery(<FONT ID="StringLiteral">"SELECT jabber_id, privileges FROM admins"</FONT>);
<A NAME="1245"></A>
<A NAME="1246"></A>        <FONT ID="While">while</FONT> (result.next()){
<A NAME="1247"></A>            adminCache.put(result.getString(<FONT ID="StringLiteral">"jabber_id"</FONT>), <FONT ID="New">new</FONT> Integer(result.getInt(<FONT ID="StringLiteral">"privileges"</FONT>)));
<A NAME="1248"></A>        }
<A NAME="1249"></A>
<A NAME="1250"></A>        } <FONT ID="Finally">finally</FONT> {
<A NAME="1251"></A>            uwr();
<A NAME="1252"></A>        }
<A NAME="1253"></A>    }
<A NAME="1254"></A>
<A NAME="1255"></A>    <FONT ID="FormalComment">/**
<A NAME="1256"></A>     * Escapes potentially harmful characters in the string (' and \ characters)
<A NAME="1257"></A>     *
<A NAME="1258"></A>     * @param   input   The string that should be escaped
<A NAME="1259"></A>     * @return      The output string
<A NAME="1260"></A>     */</FONT>
<A NAME="1261"></A>    <FONT ID="Private">private</FONT> String escapeSQL(String input){
<A NAME="1262"></A>        String output = <FONT ID="StringLiteral">""</FONT>;
<A NAME="1263"></A>        <FONT ID="Try">try</FONT> {
<A NAME="1264"></A>        <FONT ID="For">for</FONT> (<FONT ID="Int">int</FONT> i = <FONT ID="IntegerLiteral">0</FONT>; i &lt; input.length(); ++i){
<A NAME="1265"></A>            <FONT ID="If">if</FONT> (input.charAt(i)== <FONT ID="CharacerLiteral">'\''</FONT>) {
<A NAME="1266"></A>                output += <FONT ID="StringLiteral">"\\\'"</FONT>;
<A NAME="1267"></A>            } <FONT ID="Else">else</FONT> <FONT ID="If">if</FONT> (input.charAt(i) == <FONT ID="CharacerLiteral">'\\'</FONT>) {
<A NAME="1268"></A>                output += <FONT ID="StringLiteral">"\\\\"</FONT>;
<A NAME="1269"></A>            } <FONT ID="Else">else</FONT> output += input.charAt(i);
<A NAME="1270"></A>        }
<A NAME="1271"></A>        } <FONT ID="Catch">catch</FONT> (Exception e) {}
<A NAME="1272"></A>        <FONT ID="Return">return</FONT> output;
<A NAME="1273"></A>    }
<A NAME="1274"></A>
<A NAME="1275"></A>    <FONT ID="FormalComment">/**
<A NAME="1276"></A>     * Unescapes strings from the DB to their original form
<A NAME="1277"></A>     *
<A NAME="1278"></A>     * @param   input   The string to be unescaped
<A NAME="1279"></A>     * @return      The output string
<A NAME="1280"></A>     */</FONT>
<A NAME="1281"></A>    <FONT ID="Private">private</FONT> String unescapeSQL(String input){
<A NAME="1282"></A>        String output = <FONT ID="StringLiteral">""</FONT>;
<A NAME="1283"></A>        <FONT ID="Boolean">boolean</FONT> escape = <FONT ID="False">false</FONT>;
<A NAME="1284"></A>        <FONT ID="Try">try</FONT> {
<A NAME="1285"></A>        <FONT ID="For">for</FONT> (<FONT ID="Int">int</FONT> i = <FONT ID="IntegerLiteral">0</FONT>; i &lt; input.length(); ++i){
<A NAME="1286"></A>            <FONT ID="If">if</FONT> (input.charAt(i)== <FONT ID="CharacerLiteral">'\\'</FONT> &amp;&amp; !escape) {
<A NAME="1287"></A>                escape = <FONT ID="True">true</FONT>;
<A NAME="1288"></A>            } <FONT ID="Else">else</FONT> {
<A NAME="1289"></A>                escape = <FONT ID="False">false</FONT>;
<A NAME="1290"></A>                output += input.charAt(i);
<A NAME="1291"></A>            }
<A NAME="1292"></A>        }
<A NAME="1293"></A>        } <FONT ID="Catch">catch</FONT> (Exception e) {}
<A NAME="1294"></A>        <FONT ID="Return">return</FONT> output;
<A NAME="1295"></A>    }
<A NAME="1296"></A>
<A NAME="1297"></A>    <FONT ID="FormalComment">/** The connection to the DB */</FONT>
<A NAME="1298"></A>    Connection conn;
<A NAME="1299"></A>    <FONT ID="FormalComment">/** Statement instance to avoid reallocating for each DB access */</FONT>
<A NAME="1300"></A>    Statement statement;
<A NAME="1301"></A>    <FONT ID="FormalComment">/** Second statement instance for methods that return ResultSets */</FONT>
<A NAME="1302"></A>    Statement resultStatement;
<A NAME="1303"></A>    <FONT ID="FormalComment">/** Temporary result set store */</FONT>
<A NAME="1304"></A>    ResultSet result;
<A NAME="1305"></A>    <FONT ID="FormalComment">/** Reference to the time handler class instance */</FONT>
<A NAME="1306"></A>    <A HREF="../../czestmyr/jjsched/TimeHandler.java.html">TimeHandler</A> timeHandler;
<A NAME="1307"></A>    <FONT ID="FormalComment">/** Lock for the DB (used instead of transactions) */</FONT>
<A NAME="1308"></A>    ReentrantReadWriteLock dataLock = <FONT ID="New">new</FONT> ReentrantReadWriteLock();
<A NAME="1309"></A>    <FONT ID="FormalComment">/** Lock for result-set-returning statement (to ensure that it is not
<A NAME="1310"></A>        called before the previous ResultSet is not used anymore) */</FONT>
<A NAME="1311"></A>    ReentrantLock resultLock = <FONT ID="New">new</FONT> ReentrantLock();
<A NAME="1312"></A>
<A NAME="1313"></A>    <FONT ID="FormalComment">/** Cache of subscribed users, for quicker access. **/</FONT>
<A NAME="1314"></A>    HashMap&lt;String, UserData&gt; userCache;
<A NAME="1315"></A>    <FONT ID="FormalComment">/** Cache of server admins, for quicker access. **/</FONT>
<A NAME="1316"></A>    HashMap&lt;String, Integer&gt; adminCache;
<A NAME="1317"></A>    <FONT ID="FormalComment">/** Configuration options */</FONT>
<A NAME="1318"></A>    <A HREF="../../czestmyr/jjsched/Config.java.html">Config</A> conf;
<A NAME="1319"></A>}
<A NAME="1320"></A>
<A NAME="1321"></A><FONT ID="FormalComment">/** This class holds the cached data for the JJSched users */</FONT>
<A NAME="1322"></A><FONT ID="Class">class</FONT> UserData{
<A NAME="1323"></A>    UserData(<FONT ID="Long">long</FONT> newId, <FONT ID="Long">long</FONT> newOffset){
<A NAME="1324"></A>        user_id = newId;
<A NAME="1325"></A>        gmt_offset = newOffset;
<A NAME="1326"></A>    }
<A NAME="1327"></A>
<A NAME="1328"></A>    <FONT ID="Long">long</FONT> user_id;
<A NAME="1329"></A>    <FONT ID="Long">long</FONT> gmt_offset;
<A NAME="1330"></A>}
<A NAME="1331"></A></pre>
</BODY>
</HTML>